Merge "codec2: fix drain flow and EOS work reporting"
diff --git a/C2VDAAdaptor.cpp b/C2VDAAdaptor.cpp
index ecfcbef..3a960d9 100644
--- a/C2VDAAdaptor.cpp
+++ b/C2VDAAdaptor.cpp
@@ -11,6 +11,7 @@
 #include <native_pixmap_handle.h>
 #include <v4l2_device.h>
 #include <v4l2_slice_video_decode_accelerator.h>
+#include <video_pixel_format.h>
 #include <videodev2.h>
 
 #include <utils/Log.h>
@@ -80,20 +81,28 @@
 void C2VDAAdaptor::importBufferForPicture(int32_t pictureBufferId, HalPixelFormat format,
                                           int dmabufFd,
                                           const std::vector<VideoFramePlane>& planes) {
-    // per change ag/3262504, format should be passed to VDA, however it also matters to VDA API
-    // change.
-    // TODO(johnylin): pass format to VDA after updating VDA codes to latest.
-    (void)format;
-
     CHECK(mVDA);
     CHECK_LT(pictureBufferId, static_cast<int32_t>(mNumOutputBuffers));
 
+    media::VideoPixelFormat pixelFormat;
+    switch (format) {
+        case HalPixelFormat::YV12:
+            pixelFormat = media::PIXEL_FORMAT_YV12;
+            break;
+        case HalPixelFormat::NV12:
+            pixelFormat = media::PIXEL_FORMAT_NV12;
+            break;
+        default:
+            LOG_ALWAYS_FATAL("Unsupported format: 0x%x", format);
+            return;
+    }
+
     media::NativePixmapHandle handle;
     handle.fds.emplace_back(base::FileDescriptor(dmabufFd, true));
     for (const auto& plane : planes) {
         handle.planes.emplace_back(plane.mStride, plane.mOffset, 0, 0);
     }
-    mVDA->ImportBufferForPicture(pictureBufferId, handle);
+    mVDA->ImportBufferForPicture(pictureBufferId, pixelFormat, handle);
 }
 
 void C2VDAAdaptor::reusePictureBuffer(int32_t pictureBufferId) {
diff --git a/vda/accelerated_video_decoder.h b/vda/accelerated_video_decoder.h
index fe1c711..238e34d 100644
--- a/vda/accelerated_video_decoder.h
+++ b/vda/accelerated_video_decoder.h
@@ -1,6 +1,7 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 77118c9
 
 #ifndef ACCELERATED_VIDEO_DECODER_H_
 #define ACCELERATED_VIDEO_DECODER_H_
diff --git a/vda/bit_reader.cc b/vda/bit_reader.cc
index 953d144..95e7634 100644
--- a/vda/bit_reader.cc
+++ b/vda/bit_reader.cc
@@ -1,6 +1,7 @@
 // Copyright (c) 2012 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.
+// Note: ported from Chromium commit head: 2de6929
 
 #include "bit_reader.h"
 
@@ -15,7 +16,7 @@
   DCHECK_GE(size, 0);
 }
 
-BitReader::~BitReader() {}
+BitReader::~BitReader() = default;
 
 bool BitReader::ReadString(int num_bits, std::string* str) {
   DCHECK_EQ(num_bits % 8, 0);
diff --git a/vda/bit_reader.h b/vda/bit_reader.h
index 2b3fad0..dfc2b0b 100644
--- a/vda/bit_reader.h
+++ b/vda/bit_reader.h
@@ -1,6 +1,7 @@
 // Copyright (c) 2012 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.
+// Note: ported from Chromium commit head: 43ddd7a
 
 #ifndef BIT_READER_H_
 #define BIT_READER_H_
@@ -14,8 +15,7 @@
 
 namespace media {
 
-class BitReader
-    : NON_EXPORTED_BASE(private BitReaderCore::ByteStreamProvider)  {
+class BitReader : private BitReaderCore::ByteStreamProvider {
  public:
   // Initialize the reader to start reading at |data|, |size| being size
   // of |data| in bytes.
diff --git a/vda/bit_reader_core.cc b/vda/bit_reader_core.cc
index 220ea03..92b3211 100644
--- a/vda/bit_reader_core.cc
+++ b/vda/bit_reader_core.cc
@@ -1,6 +1,7 @@
 // Copyright 2014 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.
+// Note: ported from Chromium commit head: 2de6929
 
 #include "bit_reader_core.h"
 
@@ -14,11 +15,9 @@
 
 namespace media {
 
-BitReaderCore::ByteStreamProvider::ByteStreamProvider() {
-}
+BitReaderCore::ByteStreamProvider::ByteStreamProvider() = default;
 
-BitReaderCore::ByteStreamProvider::~ByteStreamProvider() {
-}
+BitReaderCore::ByteStreamProvider::~ByteStreamProvider() = default;
 
 BitReaderCore::BitReaderCore(ByteStreamProvider* byte_stream_provider)
     : byte_stream_provider_(byte_stream_provider),
@@ -29,8 +28,7 @@
       reg_next_(0) {
 }
 
-BitReaderCore::~BitReaderCore() {
-}
+BitReaderCore::~BitReaderCore() = default;
 
 bool BitReaderCore::ReadFlag(bool* flag) {
   if (nbits_ == 0 && !Refill(1))
diff --git a/vda/bit_reader_core.h b/vda/bit_reader_core.h
index 9e73018..62a21e2 100644
--- a/vda/bit_reader_core.h
+++ b/vda/bit_reader_core.h
@@ -1,6 +1,7 @@
 // Copyright 2014 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.
+// Note: ported from Chromium commit head: 1323b9c
 
 #ifndef BIT_READER_CORE_H_
 #define BIT_READER_CORE_H_
diff --git a/vda/bitstream_buffer.cc b/vda/bitstream_buffer.cc
index 4f71755..36b8d06 100644
--- a/vda/bitstream_buffer.cc
+++ b/vda/bitstream_buffer.cc
@@ -1,6 +1,7 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 2de6929
 
 #include "bitstream_buffer.h"
 
@@ -22,6 +23,6 @@
 
 BitstreamBuffer::BitstreamBuffer(const BitstreamBuffer& other) = default;
 
-BitstreamBuffer::~BitstreamBuffer() {}
+BitstreamBuffer::~BitstreamBuffer() = default;
 
 }  // namespace media
diff --git a/vda/bitstream_buffer.h b/vda/bitstream_buffer.h
index 88555a2..3a267a0 100644
--- a/vda/bitstream_buffer.h
+++ b/vda/bitstream_buffer.h
@@ -1,6 +1,7 @@
 // Copyright (c) 2011 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.
+// Note: ported from Chromium commit head: 39a7f93
 
 #ifndef MEDIA_BASE_BITSTREAM_BUFFER_H_
 #define MEDIA_BASE_BITSTREAM_BUFFER_H_
diff --git a/vda/h264_bit_reader.cc b/vda/h264_bit_reader.cc
index 7c536b3..6713655 100644
--- a/vda/h264_bit_reader.cc
+++ b/vda/h264_bit_reader.cc
@@ -1,6 +1,7 @@
 // Copyright 2014 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.
+// Note: ported from Chromium commit head: 2de6929
 
 #include "base/logging.h"
 #include "h264_bit_reader.h"
@@ -15,7 +16,7 @@
       prev_two_bytes_(0),
       emulation_prevention_bytes_(0) {}
 
-H264BitReader::~H264BitReader() {}
+H264BitReader::~H264BitReader() = default;
 
 bool H264BitReader::Initialize(const uint8_t* data, off_t size) {
   DCHECK(data);
diff --git a/vda/h264_bit_reader.h b/vda/h264_bit_reader.h
index 156b524..aa162ce 100644
--- a/vda/h264_bit_reader.h
+++ b/vda/h264_bit_reader.h
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 //
 // This file contains an implementation of an H264 Annex-B video stream parser.
+// Note: ported from Chromium commit head: 77be7ae
 
 #ifndef H264_BIT_READER_H_
 #define H264_BIT_READER_H_
diff --git a/vda/h264_decoder.cc b/vda/h264_decoder.cc
index 3964059..abaaac5 100644
--- a/vda/h264_decoder.cc
+++ b/vda/h264_decoder.cc
@@ -1,6 +1,7 @@
 // Copyright (c) 2012 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.
+// Note: ported from Chromium commit head: c3bd64c
 
 #include <algorithm>
 #include <limits>
@@ -16,22 +17,22 @@
 
 namespace media {
 
-H264Decoder::H264Accelerator::H264Accelerator() {}
+H264Decoder::H264Accelerator::H264Accelerator() = default;
 
-H264Decoder::H264Accelerator::~H264Accelerator() {}
+H264Decoder::H264Accelerator::~H264Accelerator() = default;
 
 H264Decoder::H264Decoder(H264Accelerator* accelerator)
-    : max_frame_num_(0),
+    : state_(kNeedStreamMetadata),
+      max_frame_num_(0),
       max_pic_num_(0),
       max_long_term_frame_idx_(0),
       max_num_reorder_frames_(0),
       accelerator_(accelerator) {
   DCHECK(accelerator_);
   Reset();
-  state_ = kNeedStreamMetadata;
 }
 
-H264Decoder::~H264Decoder() {}
+H264Decoder::~H264Decoder() = default;
 
 void H264Decoder::Reset() {
   curr_pic_ = nullptr;
@@ -177,6 +178,8 @@
            sizeof(curr_pic_->ref_pic_marking));
   }
 
+  curr_pic_->visible_rect = visible_rect_;
+
   return true;
 }
 
@@ -1107,10 +1110,24 @@
   if (max_dpb_mbs == 0)
     return false;
 
-  size_t max_dpb_size = std::min(max_dpb_mbs / (width_mb * height_mb),
-                                 static_cast<int>(H264DPB::kDPBMaxSize));
-  if (max_dpb_size == 0) {
-    DVLOG(1) << "Invalid DPB Size";
+  // MaxDpbFrames from level limits per spec.
+  size_t max_dpb_frames = std::min(max_dpb_mbs / (width_mb * height_mb),
+                                   static_cast<int>(H264DPB::kDPBMaxSize));
+  DVLOG(1) << "MaxDpbFrames: " << max_dpb_frames
+           << ", max_num_ref_frames: " << sps->max_num_ref_frames
+           << ", max_dec_frame_buffering: " << sps->max_dec_frame_buffering;
+
+  // Set DPB size to at least the level limit, or what the stream requires.
+  size_t max_dpb_size =
+      std::max(static_cast<int>(max_dpb_frames),
+               std::max(sps->max_num_ref_frames, sps->max_dec_frame_buffering));
+  // Some non-conforming streams specify more frames are needed than the current
+  // level limit. Allow this, but only up to the maximum number of reference
+  // frames allowed per spec.
+  DVLOG_IF(1, max_dpb_size > max_dpb_frames)
+      << "Invalid stream, DPB size > MaxDpbFrames";
+  if (max_dpb_size == 0 || max_dpb_size > H264DPB::kDPBMaxSize) {
+    DVLOG(1) << "Invalid DPB size: " << max_dpb_size;
     return false;
   }
 
@@ -1124,6 +1141,12 @@
     dpb_.set_max_num_pics(max_dpb_size);
   }
 
+  Rect new_visible_rect = sps->GetVisibleRect().value_or(Rect());
+  if (visible_rect_ != new_visible_rect) {
+    DVLOG(2) << "New visible rect: " << new_visible_rect.ToString();
+    visible_rect_ = new_visible_rect;
+  }
+
   if (!UpdateMaxNumReorderFrames(sps))
     return false;
   DVLOG(1) << "max_num_reorder_frames: " << max_num_reorder_frames_;
@@ -1320,7 +1343,7 @@
         if (state_ != kDecoding)
           break;
 
-      // else fallthrough
+        // else fallthrough
       case H264NALU::kIDRSlice: {
         // TODO(posciak): the IDR may require an SPS that we don't have
         // available. For now we'd fail if that happens, but ideally we'd like
diff --git a/vda/h264_decoder.h b/vda/h264_decoder.h
index 27a4c10..82ab98f 100644
--- a/vda/h264_decoder.h
+++ b/vda/h264_decoder.h
@@ -1,6 +1,7 @@
 // Copyright (c) 2012 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.
+// Note: ported from Chromium commit head: 77be7ae
 
 #ifndef H264_DECODER_H_
 #define H264_DECODER_H_
@@ -16,6 +17,7 @@
 #include "accelerated_video_decoder.h"
 #include "h264_dpb.h"
 #include "h264_parser.h"
+#include "rect.h"
 #include "size.h"
 
 namespace media {
@@ -266,6 +268,8 @@
 
   // Output picture size.
   Size pic_size_;
+  // Output visible cropping rect.
+  Rect visible_rect_;
 
   // PicOrderCount of the previously outputted frame.
   int last_output_poc_;
diff --git a/vda/h264_dpb.cc b/vda/h264_dpb.cc
index 0e1b411..af0b5e0 100644
--- a/vda/h264_dpb.cc
+++ b/vda/h264_dpb.cc
@@ -1,6 +1,7 @@
 // Copyright (c) 2012 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.
+// Note: ported from Chromium commit head: 2de6929
 
 #include <string.h>
 
@@ -44,14 +45,14 @@
   memset(&ref_pic_marking, 0, sizeof(ref_pic_marking));
 }
 
-H264Picture::~H264Picture() {}
+H264Picture::~H264Picture() = default;
 
 V4L2H264Picture* H264Picture::AsV4L2H264Picture() {
   return nullptr;
 }
 
 H264DPB::H264DPB() : max_num_pics_(0) {}
-H264DPB::~H264DPB() {}
+H264DPB::~H264DPB() = default;
 
 void H264DPB::Clear() {
   pics_.clear();
diff --git a/vda/h264_dpb.h b/vda/h264_dpb.h
index 6be9f21..3da284e 100644
--- a/vda/h264_dpb.h
+++ b/vda/h264_dpb.h
@@ -4,6 +4,7 @@
 //
 // This file contains an implementation of an H.264 Decoded Picture Buffer
 // used in H264 decoders.
+// Note: ported from Chromium commit head: 70340ce
 
 #ifndef H264_DPB_H_
 #define H264_DPB_H_
@@ -15,6 +16,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "h264_parser.h"
+#include "rect.h"
 
 namespace media {
 
@@ -22,7 +24,7 @@
 
 // A picture (a frame or a field) in the H.264 spec sense.
 // See spec at http://www.itu.int/rec/T-REC-H.264
-class H264Picture : public base::RefCounted<H264Picture> {
+class H264Picture : public base::RefCountedThreadSafe<H264Picture> {
  public:
   using Vector = std::vector<scoped_refptr<H264Picture>>;
 
@@ -82,8 +84,12 @@
   // Position in DPB (i.e. index in DPB).
   int dpb_position;
 
+  // The visible size of picture. This could be either parsed from SPS, or set
+  // to Rect(0, 0) for indicating invalid values or not available.
+  Rect visible_rect;
+
  protected:
-  friend class base::RefCounted<H264Picture>;
+  friend class base::RefCountedThreadSafe<H264Picture>;
   virtual ~H264Picture();
 
  private:
diff --git a/vda/h264_parser.cc b/vda/h264_parser.cc
index 0f37924..94b1e10 100644
--- a/vda/h264_parser.cc
+++ b/vda/h264_parser.cc
@@ -1,8 +1,10 @@
 // Copyright 2014 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.
+// Note: ported from Chromium commit head: 2de6929
 
 #include "h264_parser.h"
+#include "subsample_entry.h"
 
 #include <limits>
 #include <memory>
@@ -64,6 +66,60 @@
               map_unit * (pic_height_in_map_units_minus1 + 1));
 }
 
+// Also based on section 7.4.2.1.1.
+base::Optional<Rect> H264SPS::GetVisibleRect() const {
+  base::Optional<Size> coded_size = GetCodedSize();
+  if (!coded_size)
+    return base::nullopt;
+
+  if (!frame_cropping_flag)
+    return Rect(coded_size.value());
+
+  int crop_unit_x;
+  int crop_unit_y;
+  if (chroma_array_type == 0) {
+    crop_unit_x = 1;
+    crop_unit_y = frame_mbs_only_flag ? 1 : 2;
+  } else {
+    // Section 6.2.
+    // |chroma_format_idc| may be:
+    //   1 => 4:2:0
+    //   2 => 4:2:2
+    //   3 => 4:4:4
+    // Everything else has |chroma_array_type| == 0.
+    int sub_width_c = chroma_format_idc > 2 ? 1 : 2;
+    int sub_height_c = chroma_format_idc > 1 ? 1 : 2;
+    crop_unit_x = sub_width_c;
+    crop_unit_y = sub_height_c * (frame_mbs_only_flag ? 1 : 2);
+  }
+
+  // Verify that the values are not too large before multiplying.
+  if (coded_size->width() / crop_unit_x < frame_crop_left_offset ||
+      coded_size->width() / crop_unit_x < frame_crop_right_offset ||
+      coded_size->height() / crop_unit_y < frame_crop_top_offset ||
+      coded_size->height() / crop_unit_y < frame_crop_bottom_offset) {
+    DVLOG(1) << "Frame cropping exceeds coded size.";
+    return base::nullopt;
+  }
+  int crop_left = crop_unit_x * frame_crop_left_offset;
+  int crop_right = crop_unit_x * frame_crop_right_offset;
+  int crop_top = crop_unit_y * frame_crop_top_offset;
+  int crop_bottom = crop_unit_y * frame_crop_bottom_offset;
+
+  // Verify that the values are sane. Note that some decoders also require that
+  // crops are smaller than a macroblock and/or that crops must be adjacent to
+  // at least one corner of the coded frame.
+  if (coded_size->width() - crop_left <= crop_right ||
+      coded_size->height() - crop_top <= crop_bottom) {
+    DVLOG(1) << "Frame cropping excludes entire frame.";
+    return base::nullopt;
+  }
+
+  return Rect(crop_left, crop_top,
+              coded_size->width() - crop_left - crop_right,
+              coded_size->height() - crop_top - crop_bottom);
+}
+
 H264PPS::H264PPS() {
   memset(this, 0, sizeof(*this));
 }
@@ -134,12 +190,10 @@
 
 // ISO 14496 part 10
 // VUI parameters: Table E-1 "Meaning of sample aspect ratio indicator"
-static const int kTableSarWidth[] = {
-  0, 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2
-};
-static const int kTableSarHeight[] = {
-  0, 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1
-};
+static const int kTableSarWidth[] = {0,  1,  12, 10, 16,  40, 24, 20, 32,
+                                     80, 18, 15, 64, 160, 4,  3,  2};
+static const int kTableSarHeight[] = {0,  1,  11, 11, 11, 33, 11, 11, 11,
+                                      33, 11, 11, 33, 99, 3,  2,  1};
 static_assert(arraysize(kTableSarWidth) == arraysize(kTableSarHeight),
               "sar tables must have the same size");
 
@@ -147,8 +201,7 @@
   Reset();
 }
 
-H264Parser::~H264Parser() {
-}
+H264Parser::~H264Parser() = default;
 
 void H264Parser::Reset() {
   stream_ = NULL;
@@ -217,6 +270,19 @@
   off_t bytes_left = data_size;
 
   while (bytes_left >= 3) {
+    // The start code is "\0\0\1", ones are more unusual than zeroes, so let's
+    // search for it first.
+    const uint8_t* tmp =
+        reinterpret_cast<const uint8_t*>(memchr(data + 2, 1, bytes_left - 2));
+    if (!tmp) {
+      data += bytes_left - 2;
+      bytes_left = 2;
+      break;
+    }
+    tmp -= 2;
+    bytes_left -= tmp - data;
+    data = tmp;
+
     if (IsStartCode(data)) {
       // Found three-byte start code, set pointer at its beginning.
       *offset = data_size - bytes_left;
@@ -251,8 +317,7 @@
   off_t nalu_start_off = 0;
   off_t annexb_start_code_size = 0;
 
-  if (!FindStartCodeInClearRanges(stream_, bytes_left_,
-                                  encrypted_ranges_,
+  if (!FindStartCodeInClearRanges(stream_, bytes_left_, encrypted_ranges_,
                                   &nalu_start_off, &annexb_start_code_size)) {
     DVLOG(4) << "Could not find start code, end of stream?";
     return false;
@@ -277,10 +342,9 @@
   // belong to the current NALU.
   off_t next_start_code_size = 0;
   off_t nalu_size_without_start_code = 0;
-  if (!FindStartCodeInClearRanges(nalu_data, max_nalu_data_size,
-                                  encrypted_ranges_,
-                                  &nalu_size_without_start_code,
-                                  &next_start_code_size)) {
+  if (!FindStartCodeInClearRanges(
+          nalu_data, max_nalu_data_size, encrypted_ranges_,
+          &nalu_size_without_start_code, &next_start_code_size)) {
     nalu_size_without_start_code = max_nalu_data_size;
   }
   *nalu_size = nalu_size_without_start_code + annexb_start_code_size;
@@ -288,6 +352,7 @@
   return true;
 }
 
+// static
 bool H264Parser::FindStartCodeInClearRanges(
     const uint8_t* data,
     off_t data_size,
@@ -325,6 +390,30 @@
   return true;
 }
 
+// static
+bool H264Parser::ParseNALUs(const uint8_t* stream,
+                            size_t stream_size,
+                            std::vector<H264NALU>* nalus) {
+  DCHECK(nalus);
+  H264Parser parser;
+  parser.SetStream(stream, stream_size);
+
+  while (true) {
+    H264NALU nalu;
+    const H264Parser::Result result = parser.AdvanceToNextNALU(&nalu);
+    if (result == H264Parser::kOk) {
+      nalus->push_back(nalu);
+    } else if (result == media::H264Parser::kEOStream) {
+      return true;
+    } else {
+      DLOG(ERROR) << "Unexpected H264 parser result";
+      return false;
+    }
+  }
+  NOTREACHED();
+  return false;
+}
+
 H264Parser::Result H264Parser::ReadUE(int* val) {
   int num_bits = -1;
   int bit;
@@ -381,6 +470,8 @@
   if (!LocateNALU(&nalu_size_with_start_code, &start_code_size)) {
     DVLOG(4) << "Could not find next NALU, bytes left in stream: "
              << bytes_left_;
+    stream_ = nullptr;
+    bytes_left_ = 0;
     return kEOStream;
   }
 
@@ -389,8 +480,11 @@
   DVLOG(4) << "NALU found: size=" << nalu_size_with_start_code;
 
   // Initialize bit reader at the start of found NALU.
-  if (!br_.Initialize(nalu->data, nalu->size))
+  if (!br_.Initialize(nalu->data, nalu->size)) {
+    stream_ = nullptr;
+    bytes_left_ = 0;
     return kEOStream;
+  }
 
   // Move parser state to after this NALU, so next time AdvanceToNextNALU
   // is called, we will effectively be skipping it;
@@ -417,22 +511,26 @@
 
 // Default scaling lists (per spec).
 static const int kDefault4x4Intra[kH264ScalingList4x4Length] = {
-    6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42, };
+    6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42,
+};
 
 static const int kDefault4x4Inter[kH264ScalingList4x4Length] = {
-    10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34, };
+    10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34,
+};
 
 static const int kDefault8x8Intra[kH264ScalingList8x8Length] = {
     6,  10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18, 18, 18, 18, 23,
     23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27,
     27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31,
-    31, 33, 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42, };
+    31, 33, 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42,
+};
 
 static const int kDefault8x8Inter[kH264ScalingList8x8Length] = {
     9,  13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19, 19, 19, 19, 21,
     21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24,
     24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27,
-    27, 28, 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35, };
+    27, 28, 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35,
+};
 
 static inline void DefaultScalingList4x4(
     int i,
@@ -579,8 +677,7 @@
 
     if (seq_scaling_list_present_flag) {
       res = ParseScalingList(arraysize(sps->scaling_list4x4[i]),
-                             sps->scaling_list4x4[i],
-                             &use_default);
+                             sps->scaling_list4x4[i], &use_default);
       if (res != kOk)
         return res;
 
@@ -588,8 +685,8 @@
         DefaultScalingList4x4(i, sps->scaling_list4x4);
 
     } else {
-      FallbackScalingList4x4(
-          i, kDefault4x4Intra, kDefault4x4Inter, sps->scaling_list4x4);
+      FallbackScalingList4x4(i, kDefault4x4Intra, kDefault4x4Inter,
+                             sps->scaling_list4x4);
     }
   }
 
@@ -599,8 +696,7 @@
 
     if (seq_scaling_list_present_flag) {
       res = ParseScalingList(arraysize(sps->scaling_list8x8[i]),
-                             sps->scaling_list8x8[i],
-                             &use_default);
+                             sps->scaling_list8x8[i], &use_default);
       if (res != kOk)
         return res;
 
@@ -608,8 +704,8 @@
         DefaultScalingList8x8(i, sps->scaling_list8x8);
 
     } else {
-      FallbackScalingList8x8(
-          i, kDefault8x8Intra, kDefault8x8Inter, sps->scaling_list8x8);
+      FallbackScalingList8x8(i, kDefault8x8Intra, kDefault8x8Inter,
+                             sps->scaling_list8x8);
     }
   }
 
@@ -628,8 +724,7 @@
 
     if (pic_scaling_list_present_flag) {
       res = ParseScalingList(arraysize(pps->scaling_list4x4[i]),
-                             pps->scaling_list4x4[i],
-                             &use_default);
+                             pps->scaling_list4x4[i], &use_default);
       if (res != kOk)
         return res;
 
@@ -639,14 +734,12 @@
     } else {
       if (!sps.seq_scaling_matrix_present_flag) {
         // Table 7-2 fallback rule A in spec.
-        FallbackScalingList4x4(
-            i, kDefault4x4Intra, kDefault4x4Inter, pps->scaling_list4x4);
+        FallbackScalingList4x4(i, kDefault4x4Intra, kDefault4x4Inter,
+                               pps->scaling_list4x4);
       } else {
         // Table 7-2 fallback rule B in spec.
-        FallbackScalingList4x4(i,
-                               sps.scaling_list4x4[0],
-                               sps.scaling_list4x4[3],
-                               pps->scaling_list4x4);
+        FallbackScalingList4x4(i, sps.scaling_list4x4[0],
+                               sps.scaling_list4x4[3], pps->scaling_list4x4);
       }
     }
   }
@@ -657,8 +750,7 @@
 
       if (pic_scaling_list_present_flag) {
         res = ParseScalingList(arraysize(pps->scaling_list8x8[i]),
-                               pps->scaling_list8x8[i],
-                               &use_default);
+                               pps->scaling_list8x8[i], &use_default);
         if (res != kOk)
           return res;
 
@@ -668,14 +760,12 @@
       } else {
         if (!sps.seq_scaling_matrix_present_flag) {
           // Table 7-2 fallback rule A in spec.
-          FallbackScalingList8x8(
-              i, kDefault8x8Intra, kDefault8x8Inter, pps->scaling_list8x8);
+          FallbackScalingList8x8(i, kDefault8x8Intra, kDefault8x8Inter,
+                                 pps->scaling_list8x8);
         } else {
           // Table 7-2 fallback rule B in spec.
-          FallbackScalingList8x8(i,
-                                 sps.scaling_list8x8[0],
-                                 sps.scaling_list8x8[1],
-                                 pps->scaling_list8x8);
+          FallbackScalingList8x8(i, sps.scaling_list8x8[0],
+                                 sps.scaling_list8x8[1], pps->scaling_list8x8);
         }
       }
     }
@@ -697,8 +787,8 @@
   IN_RANGE_OR_RETURN(cpb_cnt_minus1, 0, 31);
   READ_BITS_OR_RETURN(8, &data);  // bit_rate_scale, cpb_size_scale
   for (int i = 0; i <= cpb_cnt_minus1; ++i) {
-    READ_UE_OR_RETURN(&data);  // bit_rate_value_minus1[i]
-    READ_UE_OR_RETURN(&data);  // cpb_size_value_minus1[i]
+    READ_UE_OR_RETURN(&data);    // bit_rate_value_minus1[i]
+    READ_UE_OR_RETURN(&data);    // cpb_size_value_minus1[i]
     READ_BOOL_OR_RETURN(&data);  // cbr_flag
   }
   READ_BITS_OR_RETURN(20, &data);  // cpb/dpb delays, etc.
@@ -755,7 +845,7 @@
     READ_BITS_OR_RETURN(16, &data);  // num_units_in_tick
     READ_BITS_OR_RETURN(16, &data);  // time_scale
     READ_BITS_OR_RETURN(16, &data);  // time_scale
-    READ_BOOL_OR_RETURN(&data);  // fixed_frame_rate_flag
+    READ_BOOL_OR_RETURN(&data);      // fixed_frame_rate_flag
   }
 
   // Read and ignore NAL HRD parameters, if present.
@@ -769,22 +859,22 @@
   if (res != kOk)
     return res;
 
-  if (hrd_parameters_present)  // One of NAL or VCL params present is enough.
+  if (hrd_parameters_present)    // One of NAL or VCL params present is enough.
     READ_BOOL_OR_RETURN(&data);  // low_delay_hrd_flag
 
   READ_BOOL_OR_RETURN(&data);  // pic_struct_present_flag
   READ_BOOL_OR_RETURN(&sps->bitstream_restriction_flag);
   if (sps->bitstream_restriction_flag) {
     READ_BOOL_OR_RETURN(&data);  // motion_vectors_over_pic_boundaries_flag
-    READ_UE_OR_RETURN(&data);  // max_bytes_per_pic_denom
-    READ_UE_OR_RETURN(&data);  // max_bits_per_mb_denom
-    READ_UE_OR_RETURN(&data);  // log2_max_mv_length_horizontal
-    READ_UE_OR_RETURN(&data);  // log2_max_mv_length_vertical
+    READ_UE_OR_RETURN(&data);    // max_bytes_per_pic_denom
+    READ_UE_OR_RETURN(&data);    // max_bits_per_mb_denom
+    READ_UE_OR_RETURN(&data);    // log2_max_mv_length_horizontal
+    READ_UE_OR_RETURN(&data);    // log2_max_mv_length_vertical
     READ_UE_OR_RETURN(&sps->max_num_reorder_frames);
     READ_UE_OR_RETURN(&sps->max_dec_frame_buffering);
     TRUE_OR_RETURN(sps->max_dec_frame_buffering >= sps->max_num_ref_frames);
-    IN_RANGE_OR_RETURN(
-        sps->max_num_reorder_frames, 0, sps->max_dec_frame_buffering);
+    IN_RANGE_OR_RETURN(sps->max_num_reorder_frames, 0,
+                       sps->max_dec_frame_buffering);
   }
 
   return kOk;
@@ -1072,7 +1162,6 @@
     int luma_log2_weight_denom,
     int chroma_log2_weight_denom,
     H264WeightingFactors* w_facts) {
-
   int def_luma_weight = 1 << luma_log2_weight_denom;
   int def_chroma_weight = 1 << chroma_log2_weight_denom;
 
@@ -1120,20 +1209,18 @@
     READ_UE_OR_RETURN(&shdr->chroma_log2_weight_denom);
   TRUE_OR_RETURN(shdr->chroma_log2_weight_denom < 8);
 
-  Result res = ParseWeightingFactors(shdr->num_ref_idx_l0_active_minus1,
-                                     sps.chroma_array_type,
-                                     shdr->luma_log2_weight_denom,
-                                     shdr->chroma_log2_weight_denom,
-                                     &shdr->pred_weight_table_l0);
+  Result res = ParseWeightingFactors(
+      shdr->num_ref_idx_l0_active_minus1, sps.chroma_array_type,
+      shdr->luma_log2_weight_denom, shdr->chroma_log2_weight_denom,
+      &shdr->pred_weight_table_l0);
   if (res != kOk)
     return res;
 
   if (shdr->IsBSlice()) {
-    res = ParseWeightingFactors(shdr->num_ref_idx_l1_active_minus1,
-                                sps.chroma_array_type,
-                                shdr->luma_log2_weight_denom,
-                                shdr->chroma_log2_weight_denom,
-                                &shdr->pred_weight_table_l1);
+    res = ParseWeightingFactors(
+        shdr->num_ref_idx_l1_active_minus1, sps.chroma_array_type,
+        shdr->luma_log2_weight_denom, shdr->chroma_log2_weight_denom,
+        &shdr->pred_weight_table_l1);
     if (res != kOk)
       return res;
   }
diff --git a/vda/h264_parser.h b/vda/h264_parser.h
index fdd3f77..a29685a 100644
--- a/vda/h264_parser.h
+++ b/vda/h264_parser.h
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 //
 // This file contains an implementation of an H264 Annex-B video stream parser.
+// Note: ported from Chromium commit head: 0a918e9
 
 #ifndef H264_PARSER_H_
 #define H264_PARSER_H_
@@ -19,6 +20,7 @@
 #include "base/optional.h"
 #include "h264_bit_reader.h"
 #include "ranges.h"
+#include "rect.h"
 #include "size.h"
 #include "subsample_entry.h"
 
@@ -142,8 +144,8 @@
   int frame_crop_bottom_offset;
 
   bool vui_parameters_present_flag;
-  int sar_width;    // Set to 0 when not specified.
-  int sar_height;   // Set to 0 when not specified.
+  int sar_width;   // Set to 0 when not specified.
+  int sar_height;  // Set to 0 when not specified.
   bool bitstream_restriction_flag;
   int max_num_reorder_frames;
   int max_dec_frame_buffering;
@@ -181,6 +183,7 @@
   // base::nullopt if they encounter integer overflow. They do not verify that
   // the results are in-spec for the given profile or level.
   base::Optional<Size> GetCodedSize() const;
+  base::Optional<Rect> GetVisibleRect() const;
 };
 
 struct H264PPS {
@@ -239,10 +242,7 @@
 struct H264SliceHeader {
   H264SliceHeader();
 
-  enum {
-    kRefListSize = 32,
-    kRefListModSize = kRefListSize
-  };
+  enum { kRefListSize = 32, kRefListModSize = kRefListSize };
 
   enum Type {
     kPSlice = 0,
@@ -258,11 +258,11 @@
   bool IsSPSlice() const;
   bool IsSISlice() const;
 
-  bool idr_pic_flag;       // from NAL header
-  int nal_ref_idc;         // from NAL header
+  bool idr_pic_flag;         // from NAL header
+  int nal_ref_idc;           // from NAL header
   const uint8_t* nalu_data;  // from NAL header
-  off_t nalu_size;         // from NAL header
-  off_t header_bit_size;   // calculated
+  off_t nalu_size;           // from NAL header
+  off_t header_bit_size;     // calculated
 
   int first_mb_in_slice;
   int slice_type;
@@ -377,6 +377,12 @@
                                          off_t* offset,
                                          off_t* start_code_size);
 
+  // Parses the input stream and returns all the NALUs through |nalus|. Returns
+  // false if the stream is invalid.
+  static bool ParseNALUs(const uint8_t* stream,
+                         size_t stream_size,
+                         std::vector<H264NALU>* nalus);
+
   H264Parser();
   ~H264Parser();
 
diff --git a/vda/native_pixmap_handle.cc b/vda/native_pixmap_handle.cc
index fa994f9..050a683 100644
--- a/vda/native_pixmap_handle.cc
+++ b/vda/native_pixmap_handle.cc
@@ -1,6 +1,7 @@
 // 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.
+// Note: ported from Chromium commit head: a9d98e6
 
 #include "native_pixmap_handle.h"
 
diff --git a/vda/native_pixmap_handle.h b/vda/native_pixmap_handle.h
index 9a284e4..62e2294 100644
--- a/vda/native_pixmap_handle.h
+++ b/vda/native_pixmap_handle.h
@@ -1,6 +1,7 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: a9d98e6
 
 #ifndef NATIVE_PIXMAP_HANDLE_H_
 #define NATIVE_PIXMAP_HANDLE_H_
@@ -14,8 +15,16 @@
 // NativePixmapPlane is used to carry the plane related information for GBM
 // buffer. More fields can be added if they are plane specific.
 struct NativePixmapPlane {
+  // This is the same value as DRM_FORMAT_MOD_INVALID, which is not a valid
+  // modifier. We use this to indicate that layout information
+  // (tiling/compression) if any will be communicated out of band.
+  static constexpr uint64_t kNoModifier = 0x00ffffffffffffffULL;
+
   NativePixmapPlane();
-  NativePixmapPlane(int stride, int offset, uint64_t size, uint64_t modifier);
+  NativePixmapPlane(int stride,
+                    int offset,
+                    uint64_t size,
+                    uint64_t modifier = kNoModifier);
   NativePixmapPlane(const NativePixmapPlane& other);
   ~NativePixmapPlane();
 
diff --git a/vda/picture.cc b/vda/picture.cc
index a086725..8933bc5 100644
--- a/vda/picture.cc
+++ b/vda/picture.cc
@@ -1,6 +1,7 @@
 // Copyright (c) 2011 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.
+// Note: ported from Chromium commit head: 2de6929
 
 #include "picture.h"
 
@@ -18,7 +19,7 @@
 
 PictureBuffer::PictureBuffer(const PictureBuffer& other) = default;
 
-PictureBuffer::~PictureBuffer() {}
+PictureBuffer::~PictureBuffer() = default;
 
 Picture::Picture(int32_t picture_buffer_id,
                  int32_t bitstream_buffer_id,
diff --git a/vda/picture.h b/vda/picture.h
index 3dbf0e9..e07b677 100644
--- a/vda/picture.h
+++ b/vda/picture.h
@@ -1,6 +1,7 @@
 // Copyright (c) 2011 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.
+// Note: ported from Chromium commit head: d264e47
 
 #ifndef PICTURE_H_
 #define PICTURE_H_
diff --git a/vda/ranges.cc b/vda/ranges.cc
index 00400b5..4394011 100644
--- a/vda/ranges.cc
+++ b/vda/ranges.cc
@@ -1,6 +1,7 @@
 // Copyright (c) 2012 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.
+// Note: ported from Chromium commit head: a4f94d3
 
 #include "ranges.h"
 
diff --git a/vda/ranges.h b/vda/ranges.h
index 98b32ce..6a76ae4 100644
--- a/vda/ranges.h
+++ b/vda/ranges.h
@@ -1,6 +1,7 @@
 // Copyright (c) 2012 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.
+// Note: ported from Chromium commit head: 1323b9c
 
 #ifndef RANGES_H_
 #define RANGES_H_
diff --git a/vda/rect.h b/vda/rect.h
index d9640b2..b23e19d 100644
--- a/vda/rect.h
+++ b/vda/rect.h
@@ -1,6 +1,8 @@
 // Copyright 2017 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.
+// Note: ported from Chromium commit head: 0e161fe
+// Note: only necessary functions are ported from gfx::Rect
 
 // Defines a simple integer rectangle class.  The containment semantics
 // are array-like; that is, the coordinate (x, y) is considered to be
diff --git a/vda/shared_memory_region.cc b/vda/shared_memory_region.cc
index ed56559..775a5f2 100644
--- a/vda/shared_memory_region.cc
+++ b/vda/shared_memory_region.cc
@@ -1,6 +1,7 @@
 // Copyright (c) 2015 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.
+// Note: ported from Chromium commit head: 60f9667
 
 #include "base/sys_info.h"
 #include "shared_memory_region.h"
diff --git a/vda/shared_memory_region.h b/vda/shared_memory_region.h
index ce9a322..3c5d4b3 100644
--- a/vda/shared_memory_region.h
+++ b/vda/shared_memory_region.h
@@ -1,6 +1,7 @@
 // Copyright (c) 2015 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.
+// Note: ported from Chromium commit head: 60f9667
 
 #ifndef SHARED_MEMORY_REGION_H_
 #define SHARED_MEMORY_REGION_H_
diff --git a/vda/size.h b/vda/size.h
index 4806ddc..c3e8c82 100644
--- a/vda/size.h
+++ b/vda/size.h
@@ -1,6 +1,8 @@
 // Copyright 2017 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.
+// Note: ported from Chromium commit head: a8e9f71
+// Note: only necessary functions are ported from gfx::Size
 
 #ifndef SIZE_H_
 #define SIZE_H_
diff --git a/vda/subsample_entry.h b/vda/subsample_entry.h
index e7529fb..1e0bfad 100644
--- a/vda/subsample_entry.h
+++ b/vda/subsample_entry.h
@@ -1,6 +1,7 @@
 // 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.
+// Note: ported from Chromium commit head: 7014d6d
 
 #ifndef SUBSAMPLE_ENTRY_H_
 #define SUBSAMPLE_ENTRY_H_
diff --git a/vda/v4l2_device.cc b/vda/v4l2_device.cc
index 16446d3..78ef474 100644
--- a/vda/v4l2_device.cc
+++ b/vda/v4l2_device.cc
@@ -1,6 +1,8 @@
 // Copyright 2014 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.
+// Note: ported from Chromium commit head: 09ea0d2
+// Note: it's also merged with generic_v4l2_device.cc (head: a9d98e6)
 
 #include <errno.h>
 #include <fcntl.h>
@@ -15,6 +17,10 @@
 #include "base/strings/stringprintf.h"
 #include "v4l2_device.h"
 
+#define DVLOGF(level) DVLOG(level) << __func__ << "(): "
+#define VLOGF(level) VLOG(level) << __func__ << "(): "
+#define VPLOGF(level) VPLOG(level) << __func__ << "(): "
+
 namespace media {
 
 V4L2Device::V4L2Device() {}
@@ -47,7 +53,7 @@
       return PIXEL_FORMAT_ARGB;
 
     default:
-      DVLOG(1) << "Add more cases as needed";
+      DVLOGF(1) << "Add more cases as needed";
       return PIXEL_FORMAT_UNKNOWN;
   }
 }
@@ -131,7 +137,7 @@
       break;
 
     default:
-      DVLOG(1) << "Unhandled pixelformat " << std::hex << "0x" << pix_fmt;
+      VLOGF(1) << "Unhandled pixelformat " << std::hex << "0x" << pix_fmt;
       return profiles;
   }
 
@@ -156,7 +162,7 @@
   nfds = 1;
 
   if (poll_device) {
-    DVLOG(3) << "Poll(): adding device fd to poll() set";
+    DVLOGF(5) << "Poll(): adding device fd to poll() set";
     pollfds[nfds].fd = device_fd_.get();
     pollfds[nfds].events = POLLIN | POLLOUT | POLLERR | POLLPRI;
     pollfd = nfds;
@@ -164,7 +170,7 @@
   }
 
   if (HANDLE_EINTR(poll(pollfds, nfds, -1)) == -1) {
-    DPLOG(ERROR) << "poll() failed";
+    VPLOGF(1) << "poll() failed";
     return false;
   }
   *event_pending = (pollfd != -1 && pollfds[pollfd].revents & POLLPRI);
@@ -185,19 +191,19 @@
 }
 
 bool V4L2Device::SetDevicePollInterrupt() {
-  DVLOG(3) << "SetDevicePollInterrupt()";
+  DVLOGF(4);
 
   const uint64_t buf = 1;
   if (HANDLE_EINTR(write(device_poll_interrupt_fd_.get(), &buf, sizeof(buf))) ==
       -1) {
-    DPLOG(ERROR) << "SetDevicePollInterrupt(): write() failed";
+    VPLOGF(1) << "write() failed";
     return false;
   }
   return true;
 }
 
 bool V4L2Device::ClearDevicePollInterrupt() {
-  DVLOG(3) << "ClearDevicePollInterrupt()";
+  DVLOGF(5);
 
   uint64_t buf;
   if (HANDLE_EINTR(read(device_poll_interrupt_fd_.get(), &buf, sizeof(buf))) ==
@@ -206,7 +212,7 @@
       // No interrupt flag set, and we're reading nonblocking.  Not an error.
       return true;
     } else {
-      DPLOG(ERROR) << "ClearDevicePollInterrupt(): read() failed";
+      VPLOGF(1) << "read() failed";
       return false;
     }
   }
@@ -214,22 +220,23 @@
 }
 
 bool V4L2Device::Open(Type type, uint32_t v4l2_pixfmt) {
+  VLOGF(2);
   std::string path = GetDevicePathFor(type, v4l2_pixfmt);
 
   if (path.empty()) {
-    DVLOG(1) << "No devices supporting " << std::hex << "0x" << v4l2_pixfmt
+    VLOGF(1) << "No devices supporting " << std::hex << "0x" << v4l2_pixfmt
              << " for type: " << static_cast<int>(type);
     return false;
   }
 
   if (!OpenDevicePath(path, type)) {
-    LOG(ERROR) << "Failed opening " << path;
+    VLOGF(1) << "Failed opening " << path;
     return false;
   }
 
   device_poll_interrupt_fd_.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
   if (!device_poll_interrupt_fd_.is_valid()) {
-    LOG(ERROR) << "Failed creating a poll interrupt fd";
+    VLOGF(1) << "Failed creating a poll interrupt fd";
     return false;
   }
 
@@ -240,6 +247,7 @@
     int index,
     size_t num_planes,
     enum v4l2_buf_type buf_type) {
+  VLOGF(2);
   DCHECK(V4L2_TYPE_IS_MULTIPLANAR(buf_type));
 
   std::vector<base::ScopedFD> dmabuf_fds;
@@ -270,7 +278,7 @@
   const auto& devices = GetDevicesForType(type);
   for (const auto& device : devices) {
     if (!OpenDevicePath(device.first, type)) {
-      LOG(ERROR) << "Failed opening " << device.first;
+      VLOGF(1) << "Failed opening " << device.first;
       continue;
     }
 
@@ -320,15 +328,15 @@
   }
   if (max_resolution->IsEmpty()) {
     max_resolution->SetSize(1920, 1088);
-    LOG(ERROR) << "GetSupportedResolution failed to get maximum resolution for "
-               << "fourcc " << std::hex << pixelformat
-               << ", fall back to " << max_resolution->ToString();
+    VLOGF(1) << "GetSupportedResolution failed to get maximum resolution for "
+             << "fourcc " << std::hex << pixelformat
+             << ", fall back to " << max_resolution->ToString();
   }
   if (min_resolution->IsEmpty()) {
     min_resolution->SetSize(16, 16);
-    LOG(ERROR) << "GetSupportedResolution failed to get minimum resolution for "
-               << "fourcc " << std::hex << pixelformat
-               << ", fall back to " << min_resolution->ToString();
+    VLOGF(1) << "GetSupportedResolution failed to get minimum resolution for "
+             << "fourcc " << std::hex << pixelformat
+             << ", fall back to " << min_resolution->ToString();
   }
 }
 
@@ -341,8 +349,8 @@
   fmtdesc.type = buf_type;
 
   for (; Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) {
-    DVLOG(1) << "Found " << fmtdesc.description << std::hex << " (0x"
-             << fmtdesc.pixelformat << ")";
+    DVLOGF(3) << "Found " << fmtdesc.description << std::hex << " (0x"
+              << fmtdesc.pixelformat << ")";
     pixelformats.push_back(fmtdesc.pixelformat);
   }
 
@@ -373,9 +381,9 @@
       profile.profile = video_codec_profile;
       profiles.push_back(profile);
 
-      DVLOG(1) << "Found decoder profile " << GetProfileName(profile.profile)
-               << ", resolutions: " << profile.min_resolution.ToString() << " "
-               << profile.max_resolution.ToString();
+      DVLOGF(3) << "Found decoder profile " << GetProfileName(profile.profile)
+                << ", resolutions: " << profile.min_resolution.ToString() << " "
+                << profile.max_resolution.ToString();
     }
   }
 
@@ -394,6 +402,7 @@
 }
 
 void V4L2Device::CloseDevice() {
+  VLOGF(2);
   device_fd_.reset();
 }
 
@@ -433,7 +442,7 @@
     const auto& supported_pixelformats =
         EnumerateSupportedPixelformats(buf_type);
     if (!supported_pixelformats.empty()) {
-      DVLOG(1) << "Found device: " << path;
+      DVLOGF(3) << "Found device: " << path;
       devices.push_back(std::make_pair(path, supported_pixelformats));
     }
 
diff --git a/vda/v4l2_device.h b/vda/v4l2_device.h
index 41dd616..f64cbf7 100644
--- a/vda/v4l2_device.h
+++ b/vda/v4l2_device.h
@@ -5,6 +5,8 @@
 // This file defines the V4L2Device interface which is used by the
 // V4L2DecodeAccelerator class to delegate/pass the device specific
 // handling of any of the functionalities.
+// Note: ported from Chromium commit head: fb70f64
+// Note: it's also merged with generic_v4l2_device.h (head: fb70f64)
 
 #ifndef V4L2_DEVICE_H_
 #define V4L2_DEVICE_H_
diff --git a/vda/v4l2_slice_video_decode_accelerator.cc b/vda/v4l2_slice_video_decode_accelerator.cc
index fcbf614..5da373a 100644
--- a/vda/v4l2_slice_video_decode_accelerator.cc
+++ b/vda/v4l2_slice_video_decode_accelerator.cc
@@ -1,6 +1,7 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 85fdf90
 
 #include "v4l2_slice_video_decode_accelerator.h"
 
@@ -27,21 +28,20 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "shared_memory_region.h"
 
-#define LOGF(level) LOG(level) << __func__ << "(): "
-#define DLOGF(level) DLOG(level) << __func__ << "(): "
 #define DVLOGF(level) DVLOG(level) << __func__ << "(): "
-#define PLOGF(level) PLOG(level) << __func__ << "(): "
+#define VLOGF(level) VLOG(level) << __func__ << "(): "
+#define VPLOGF(level) VPLOG(level) << __func__ << "(): "
 
-#define NOTIFY_ERROR(x)                         \
-  do {                                          \
-    LOGF(ERROR) << "Setting error state:" << x; \
-    SetErrorState(x);                           \
+#define NOTIFY_ERROR(x)                       \
+  do {                                        \
+    VLOGF(1) << "Setting error state: " << x; \
+    SetErrorState(x);                         \
   } while (0)
 
 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_str) \
   do {                                                          \
     if (device_->Ioctl(type, arg) != 0) {                       \
-      PLOGF(ERROR) << "ioctl() failed: " << type_str;           \
+      VPLOGF(1) << "ioctl() failed: " << type_str;              \
       return value;                                             \
     }                                                           \
   } while (0)
@@ -52,10 +52,10 @@
 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \
   IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false, #type)
 
-#define IOCTL_OR_LOG_ERROR(type, arg)              \
-  do {                                             \
-    if (device_->Ioctl(type, arg) != 0)            \
-      PLOGF(ERROR) << "ioctl() failed: " << #type; \
+#define IOCTL_OR_LOG_ERROR(type, arg)           \
+  do {                                          \
+    if (device_->Ioctl(type, arg) != 0)         \
+      VPLOGF(1) << "ioctl() failed: " << #type; \
   } while (0)
 
 namespace media {
@@ -84,6 +84,11 @@
   int input_record() const { return input_record_; }
   int output_record() const { return output_record_; }
   uint32_t config_store() const { return config_store_; }
+  Rect visible_rect() const { return visible_rect_; }
+
+  void set_visible_rect(const Rect& visible_rect) {
+    visible_rect_ = visible_rect;
+  }
 
   // Take references to each reference surface and keep them until the
   // target surface is decoded.
@@ -108,6 +113,7 @@
   int input_record_;
   int output_record_;
   uint32_t config_store_;
+  Rect visible_rect_;
 
   bool decoded_;
   ReleaseCB release_cb_;
@@ -474,7 +480,7 @@
 
 bool V4L2SliceVideoDecodeAccelerator::Initialize(const Config& config,
                                                  Client* client) {
-  DVLOGF(3) << "profile: " << config.profile;
+  VLOGF(3) << "profile: " << config.profile;
   DCHECK(child_task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, kUninitialized);
 
@@ -506,8 +512,8 @@
       V4L2Device::VideoCodecProfileToV4L2PixFmt(video_profile_, true);
 
   if (!device_->Open(V4L2Device::Type::kDecoder, input_format_fourcc_)) {
-    DVLOGF(1) << "Failed to open device for profile: " << config.profile
-              << " fourcc: " << std::hex << "0x" << input_format_fourcc_;
+    VLOGF(1) << "Failed to open device for profile: " << config.profile
+             << " fourcc: " << std::hex << "0x" << input_format_fourcc_;
     return false;
   }
 
@@ -532,8 +538,8 @@
   const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
   IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps);
   if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
-    LOGF(ERROR) << "ioctl() failed: VIDIOC_QUERYCAP"
-                << ", caps check failed: 0x" << std::hex << caps.capabilities;
+    VLOGF(1) << "ioctl() failed: VIDIOC_QUERYCAP"
+             << ", caps check failed: 0x" << std::hex << caps.capabilities;
     return false;
   }
 
@@ -541,7 +547,7 @@
     return false;
 
   if (!decoder_thread_.Start()) {
-    DLOGF(ERROR) << "device thread failed to start";
+    VLOGF(1) << "device thread failed to start";
     return false;
   }
   decoder_thread_task_runner_ = decoder_thread_.task_runner();
@@ -554,12 +560,12 @@
       FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::InitializeTask,
                             base::Unretained(this)));
 
-  DVLOGF(1) << "V4L2SliceVideoDecodeAccelerator initialized";
+  VLOGF(2) << "V4L2SliceVideoDecodeAccelerator initialized";
   return true;
 }
 
 void V4L2SliceVideoDecodeAccelerator::InitializeTask() {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, kInitialized);
 
@@ -572,7 +578,7 @@
 }
 
 void V4L2SliceVideoDecodeAccelerator::Destroy() {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(child_task_runner_->BelongsToCurrentThread());
 
   if (decoder_thread_.IsRunning()) {
@@ -585,11 +591,11 @@
   }
 
   delete this;
-  DVLOGF(3) << "Destroyed";
+  VLOGF(2) << "Destroyed";
 }
 
 void V4L2SliceVideoDecodeAccelerator::DestroyTask() {
-  DVLOGF(3);
+  DVLOGF(2);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
   state_ = kError;
@@ -675,7 +681,7 @@
   }
 
   if (output_format_fourcc_ == 0) {
-    LOGF(ERROR) << "Could not find a usable output format";
+    VLOGF(1) << "Could not find a usable output format";
     return false;
   }
 
@@ -691,7 +697,7 @@
 }
 
 bool V4L2SliceVideoDecodeAccelerator::CreateInputBuffers() {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
   DCHECK(!input_streamon_);
   DCHECK(input_buffer_map_.empty());
@@ -703,7 +709,7 @@
   reqbufs.memory = V4L2_MEMORY_MMAP;
   IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
   if (reqbufs.count < kNumInputBuffers) {
-    PLOGF(ERROR) << "Could not allocate enough output buffers";
+    VLOGF(1) << "Could not allocate enough output buffers";
     return false;
   }
   input_buffer_map_.resize(reqbufs.count);
@@ -727,7 +733,7 @@
                                   MAP_SHARED,
                                   buffer.m.planes[0].m.mem_offset);
     if (address == MAP_FAILED) {
-      PLOGF(ERROR) << "mmap() failed";
+      VLOGF(1) << "mmap() failed";
       return false;
     }
     input_buffer_map_[i].address = address;
@@ -738,29 +744,29 @@
 }
 
 bool V4L2SliceVideoDecodeAccelerator::CreateOutputBuffers() {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
   DCHECK(!output_streamon_);
   DCHECK(output_buffer_map_.empty());
   DCHECK(surfaces_at_display_.empty());
   DCHECK(surfaces_at_device_.empty());
 
-  visible_size_ = decoder_->GetPicSize();
+  Size pic_size = decoder_->GetPicSize();
   size_t num_pictures = decoder_->GetRequiredNumOfPictures();
 
   DCHECK_GT(num_pictures, 0u);
-  DCHECK(!visible_size_.IsEmpty());
+  DCHECK(!pic_size.IsEmpty());
 
   struct v4l2_format format;
   memset(&format, 0, sizeof(format));
   format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
   format.fmt.pix_mp.pixelformat = output_format_fourcc_;
-  format.fmt.pix_mp.width = visible_size_.width();
-  format.fmt.pix_mp.height = visible_size_.height();
+  format.fmt.pix_mp.width = pic_size.width();
+  format.fmt.pix_mp.height = pic_size.height();
   format.fmt.pix_mp.num_planes = input_planes_count_;
 
   if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0) {
-    PLOGF(ERROR) << "Failed setting format to: " << output_format_fourcc_;
+    VPLOGF(1) << "Failed setting format to: " << output_format_fourcc_;
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return false;
   }
@@ -770,22 +776,17 @@
   DCHECK_EQ(coded_size_.width() % 16, 0);
   DCHECK_EQ(coded_size_.height() % 16, 0);
 
-  if (!Rect(coded_size_).Contains(Rect(visible_size_))) {
-    LOGF(ERROR) << "Got invalid adjusted coded size: "
-                << coded_size_.ToString();
+  if (!Rect(coded_size_).Contains(Rect(pic_size))) {
+    VLOGF(1) << "Got invalid adjusted coded size: " << coded_size_.ToString();
     return false;
   }
 
   DVLOGF(3) << "buffer_count=" << num_pictures
-            << ", visible size=" << visible_size_.ToString()
+            << ", pic size=" << pic_size.ToString()
             << ", coded size=" << coded_size_.ToString();
 
-  // With ALLOCATE mode the client can sample it as RGB and doesn't need to
-  // know the precise format.
   VideoPixelFormat pixel_format =
-      (output_mode_ == Config::OutputMode::IMPORT)
-          ? V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_)
-          : PIXEL_FORMAT_UNKNOWN;
+      V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_);
 
   child_task_runner_->PostTask(
       FROM_HERE,
@@ -805,7 +806,7 @@
 }
 
 void V4L2SliceVideoDecodeAccelerator::DestroyInputBuffers() {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread() ||
          !decoder_thread_.IsRunning());
   DCHECK(!input_streamon_);
@@ -836,7 +837,7 @@
   DCHECK(child_task_runner_->BelongsToCurrentThread());
 
   for (auto picture_buffer_id : picture_buffer_ids) {
-    DVLOGF(1) << "dismissing PictureBuffer id=" << picture_buffer_id;
+    DVLOGF(4) << "dismissing PictureBuffer id=" << picture_buffer_id;
     client_->DismissPictureBuffer(picture_buffer_id);
   }
 
@@ -844,7 +845,7 @@
 }
 
 void V4L2SliceVideoDecodeAccelerator::DevicePollTask(bool poll_device) {
-  DVLOGF(4);
+  DVLOGF(3);
   DCHECK(device_poll_thread_.task_runner()->BelongsToCurrentThread());
 
   bool event_pending;
@@ -874,7 +875,7 @@
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
   if (!device_poll_thread_.IsRunning()) {
-    DVLOGF(2) << "Device poll thread stopped, will not schedule poll";
+    DVLOGF(4) << "Device poll thread stopped, will not schedule poll";
     return;
   }
 
@@ -891,7 +892,7 @@
       FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DevicePollTask,
                             base::Unretained(this), true));
 
-  DVLOGF(2) << "buffer counts: "
+  DVLOGF(3) << "buffer counts: "
             << "INPUT[" << decoder_input_queue_.size() << "]"
             << " => DEVICE["
             << free_input_buffers_.size() << "+"
@@ -913,13 +914,13 @@
 
   if (!EnqueueInputRecord(dec_surface->input_record(),
                           dec_surface->config_store())) {
-    DVLOGF(1) << "Failed queueing an input buffer";
+    VLOGF(1) << "Failed queueing an input buffer";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return;
   }
 
   if (!EnqueueOutputRecord(dec_surface->output_record())) {
-    DVLOGF(1) << "Failed queueing an output buffer";
+    VLOGF(1) << "Failed queueing an output buffer";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return;
   }
@@ -935,7 +936,7 @@
 }
 
 void V4L2SliceVideoDecodeAccelerator::Dequeue() {
-  DVLOGF(3);
+  DVLOGF(4);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
   struct v4l2_buffer dqbuf;
@@ -953,7 +954,7 @@
         // EAGAIN if we're just out of buffers to dequeue.
         break;
       }
-      PLOGF(ERROR) << "ioctl() failed: VIDIOC_DQBUF";
+      VPLOGF(1) << "ioctl() failed: VIDIOC_DQBUF";
       NOTIFY_ERROR(PLATFORM_FAILURE);
       return;
     }
@@ -981,7 +982,7 @@
         // EAGAIN if we're just out of buffers to dequeue.
         break;
       }
-      PLOGF(ERROR) << "ioctl() failed: VIDIOC_DQBUF";
+      VPLOGF(1) << "ioctl() failed: VIDIOC_DQBUF";
       NOTIFY_ERROR(PLATFORM_FAILURE);
       return;
     }
@@ -989,13 +990,13 @@
     DCHECK(output_record.at_device);
     output_record.at_device = false;
     output_buffer_queued_count_--;
-    DVLOGF(3) << "Dequeued output=" << dqbuf.index
-              << " count " << output_buffer_queued_count_;
+    DVLOGF(4) << "Dequeued output=" << dqbuf.index << " count "
+              << output_buffer_queued_count_;
 
     V4L2DecodeSurfaceByOutputId::iterator it =
         surfaces_at_device_.find(dqbuf.index);
     if (it == surfaces_at_device_.end()) {
-      DLOGF(ERROR) << "Got invalid surface from device.";
+      VLOGF(1) << "Got invalid surface from device.";
       NOTIFY_ERROR(PLATFORM_FAILURE);
     }
 
@@ -1090,7 +1091,7 @@
 bool V4L2SliceVideoDecodeAccelerator::EnqueueInputRecord(
     int index,
     uint32_t config_store) {
-  DVLOGF(3);
+  DVLOGF(4);
   DCHECK_LT(index, static_cast<int>(input_buffer_map_.size()));
   DCHECK_GT(config_store, 0u);
 
@@ -1118,7 +1119,7 @@
 }
 
 bool V4L2SliceVideoDecodeAccelerator::EnqueueOutputRecord(int index) {
-  DVLOGF(3);
+  DVLOGF(4);
   DCHECK_LT(index, static_cast<int>(output_buffer_map_.size()));
 
   // Enqueue an output (VIDEO_CAPTURE) buffer.
@@ -1161,7 +1162,7 @@
 
   // Start up the device poll thread and schedule its first DevicePollTask().
   if (!device_poll_thread_.Start()) {
-    DLOGF(ERROR) << "Device thread failed to start";
+    VLOGF(1) << "Device thread failed to start";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return false;
   }
@@ -1191,7 +1192,7 @@
 
   // Signal the DevicePollTask() to stop, and stop the device poll thread.
   if (!device_->SetDevicePollInterrupt()) {
-    PLOGF(ERROR) << "SetDevicePollInterrupt(): failed";
+    VPLOGF(1) << "SetDevicePollInterrupt(): failed";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return false;
   }
@@ -1253,12 +1254,12 @@
 
 void V4L2SliceVideoDecodeAccelerator::Decode(
     const BitstreamBuffer& bitstream_buffer) {
-  DVLOGF(3) << "input_id=" << bitstream_buffer.id()
+  DVLOGF(4) << "input_id=" << bitstream_buffer.id()
             << ", size=" << bitstream_buffer.size();
   DCHECK(decode_task_runner_->BelongsToCurrentThread());
 
   if (bitstream_buffer.id() < 0) {
-    LOGF(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id();
+    VLOGF(1) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id();
     if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle()))
       base::SharedMemory::CloseHandle(bitstream_buffer.handle());
     NOTIFY_ERROR(INVALID_ARGUMENT);
@@ -1272,7 +1273,7 @@
 
 void V4L2SliceVideoDecodeAccelerator::DecodeTask(
     const BitstreamBuffer& bitstream_buffer) {
-  DVLOGF(3) << "input_id=" << bitstream_buffer.id()
+  DVLOGF(4) << "input_id=" << bitstream_buffer.id()
             << " size=" << bitstream_buffer.size();
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
@@ -1285,11 +1286,11 @@
     return;
 
   if (!bitstream_record->shm->Map()) {
-    LOGF(ERROR) << "Could not map bitstream_buffer";
+    VLOGF(1) << "Could not map bitstream_buffer";
     NOTIFY_ERROR(UNREADABLE_INPUT);
     return;
   }
-  DVLOGF(3) << "mapped at=" << bitstream_record->shm->memory();
+  DVLOGF(4) << "mapped at=" << bitstream_record->shm->memory();
 
   decoder_input_queue_.push(
       linked_ptr<BitstreamBufferRef>(bitstream_record.release()));
@@ -1333,7 +1334,7 @@
 }
 
 void V4L2SliceVideoDecodeAccelerator::DecodeBufferTask() {
-  DVLOGF(3);
+  DVLOGF(4);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
   if (state_ != kDecoding) {
@@ -1346,7 +1347,7 @@
     res = decoder_->Decode();
     switch (res) {
       case AcceleratedVideoDecoder::kAllocateNewSurfaces:
-        DVLOGF(2) << "Decoder requesting a new set of surfaces";
+        VLOGF(2) << "Decoder requesting a new set of surfaces";
         InitiateSurfaceSetChange();
         return;
 
@@ -1367,7 +1368,7 @@
         return;
 
       case AcceleratedVideoDecoder::kDecodeError:
-        DVLOGF(1) << "Error decoding stream";
+        VLOGF(1) << "Error decoding stream";
         NOTIFY_ERROR(PLATFORM_FAILURE);
         return;
     }
@@ -1375,7 +1376,7 @@
 }
 
 void V4L2SliceVideoDecodeAccelerator::InitiateSurfaceSetChange() {
-  DVLOGF(2);
+  VLOGF(2);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, kDecoding);
 
@@ -1385,7 +1386,7 @@
 }
 
 bool V4L2SliceVideoDecodeAccelerator::FinishSurfaceSetChange() {
-  DVLOGF(2);
+  VLOGF(2);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
   if (!surface_set_change_pending_)
@@ -1408,6 +1409,12 @@
     return false;
   }
 
+  // Dequeued decoded surfaces may be pended in pending_picture_ready_ if they
+  // are waiting for some pictures to be cleared. We should post them right away
+  // because they are about to be dismissed and destroyed for surface set
+  // change.
+  SendPictureReady();
+
   // This will return only once all buffers are dismissed and destroyed.
   // This does not wait until they are displayed however, as display retains
   // references to the buffers bound to textures and will release them
@@ -1423,12 +1430,12 @@
   }
 
   surface_set_change_pending_ = false;
-  DVLOGF(3) << "Surface set change finished";
+  VLOGF(2) << "Surface set change finished";
   return true;
 }
 
 bool V4L2SliceVideoDecodeAccelerator::DestroyOutputs(bool dismiss) {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
   std::vector<int32_t> picture_buffers_to_dismiss;
 
@@ -1441,7 +1448,7 @@
   }
 
   if (dismiss) {
-    DVLOGF(2) << "Scheduling picture dismissal";
+    VLOGF(2) << "Scheduling picture dismissal";
     base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                              base::WaitableEvent::InitialState::NOT_SIGNALED);
     child_task_runner_->PostTask(
@@ -1456,7 +1463,7 @@
 }
 
 bool V4L2SliceVideoDecodeAccelerator::DestroyOutputBuffers() {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread() ||
          !decoder_thread_.IsRunning());
   DCHECK(!output_streamon_);
@@ -1498,7 +1505,7 @@
 
 void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffers(
     const std::vector<PictureBuffer>& buffers) {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(child_task_runner_->BelongsToCurrentThread());
 
   decoder_thread_task_runner_->PostTask(
@@ -1509,16 +1516,16 @@
 
 void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffersTask(
     const std::vector<PictureBuffer>& buffers) {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, kAwaitingPictureBuffers);
 
   const uint32_t req_buffer_count = decoder_->GetRequiredNumOfPictures();
 
   if (buffers.size() < req_buffer_count) {
-    DLOG(ERROR) << "Failed to provide requested picture buffers. "
-                << "(Got " << buffers.size()
-                << ", requested " << req_buffer_count << ")";
+    VLOGF(1) << "Failed to provide requested picture buffers. "
+             << "(Got " << buffers.size() << ", requested " << req_buffer_count
+             << ")";
     NOTIFY_ERROR(INVALID_ARGUMENT);
     return;
   }
@@ -1534,7 +1541,7 @@
   IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs);
 
   if (reqbufs.count != buffers.size()) {
-    DLOGF(ERROR) << "Could not allocate enough output buffers";
+    VLOGF(1) << "Could not allocate enough output buffers";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return;
   }
@@ -1587,6 +1594,7 @@
 
 void V4L2SliceVideoDecodeAccelerator::ImportBufferForPicture(
     int32_t picture_buffer_id,
+    VideoPixelFormat pixel_format,
     const NativePixmapHandle& native_pixmap_handle) {
   DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id;
   DCHECK(child_task_runner_->BelongsToCurrentThread());
@@ -1598,7 +1606,14 @@
   }
 
   if (output_mode_ != Config::OutputMode::IMPORT) {
-    LOGF(ERROR) << "Cannot import in non-import mode";
+    VLOGF(1) << "Cannot import in non-import mode";
+    NOTIFY_ERROR(INVALID_ARGUMENT);
+    return;
+  }
+
+  if (pixel_format !=
+      V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_)) {
+    VLOGF(1) << "Unsupported import format: " << pixel_format;
     NOTIFY_ERROR(INVALID_ARGUMENT);
     return;
   }
@@ -1632,7 +1647,7 @@
   }
 
   if (!iter->at_client) {
-    LOGF(ERROR) << "Cannot import buffer that not owned by client";
+    VLOGF(1) << "Cannot import buffer that not owned by client";
     NOTIFY_ERROR(INVALID_ARGUMENT);
     return;
   }
@@ -1664,7 +1679,7 @@
 
 void V4L2SliceVideoDecodeAccelerator::ReusePictureBufferTask(
     int32_t picture_buffer_id) {
-  DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id;
+  DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id;
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
   V4L2DecodeSurfaceByPictureBufferId::iterator it =
@@ -1682,7 +1697,7 @@
 
   OutputRecord& output_record = output_buffer_map_[it->second->output_record()];
   if (output_record.at_device || !output_record.at_client) {
-    DVLOGF(1) << "picture_buffer_id not reusable";
+    VLOGF(1) << "picture_buffer_id not reusable";
     NOTIFY_ERROR(INVALID_ARGUMENT);
     return;
   }
@@ -1694,7 +1709,7 @@
 }
 
 void V4L2SliceVideoDecodeAccelerator::Flush() {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(child_task_runner_->BelongsToCurrentThread());
 
   decoder_thread_task_runner_->PostTask(
@@ -1703,7 +1718,7 @@
 }
 
 void V4L2SliceVideoDecodeAccelerator::FlushTask() {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
   // Queue an empty buffer which - when reached - will trigger flush sequence.
@@ -1715,7 +1730,7 @@
 }
 
 void V4L2SliceVideoDecodeAccelerator::InitiateFlush() {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
   // This will trigger output for all remaining surfaces in the decoder.
@@ -1736,7 +1751,7 @@
 }
 
 bool V4L2SliceVideoDecodeAccelerator::FinishFlush() {
-  DVLOGF(3);
+  VLOGF(4);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
   if (!decoder_flushing_)
@@ -1762,7 +1777,7 @@
   SendPictureReady();
 
   decoder_flushing_ = false;
-  DVLOGF(3) << "Flush finished";
+  VLOGF(2) << "Flush finished";
 
   child_task_runner_->PostTask(FROM_HERE,
                                base::Bind(&Client::NotifyFlushDone, client_));
@@ -1771,7 +1786,7 @@
 }
 
 void V4L2SliceVideoDecodeAccelerator::Reset() {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(child_task_runner_->BelongsToCurrentThread());
 
   decoder_thread_task_runner_->PostTask(
@@ -1780,7 +1795,7 @@
 }
 
 void V4L2SliceVideoDecodeAccelerator::ResetTask() {
-  DVLOGF(3);
+  VLOGF(2);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
   if (decoder_resetting_) {
@@ -1803,7 +1818,7 @@
 }
 
 bool V4L2SliceVideoDecodeAccelerator::FinishReset() {
-  DVLOGF(3);
+  VLOGF(4);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
   if (!decoder_resetting_)
@@ -1834,7 +1849,7 @@
   }
 
   decoder_resetting_ = false;
-  DVLOGF(3) << "Reset finished";
+  VLOGF(2) << "Reset finished";
 
   child_task_runner_->PostTask(FROM_HERE,
                                base::Bind(&Client::NotifyResetDone, client_));
@@ -1898,7 +1913,7 @@
   size_t i = 0;
   for (const auto& pic : dpb) {
     if (i >= arraysize(v4l2_decode_param_.dpb)) {
-      DVLOGF(1) << "Invalid DPB size";
+      VLOGF(1) << "Invalid DPB size";
       break;
     }
 
@@ -2108,7 +2123,7 @@
     const uint8_t* data,
     size_t size) {
   if (num_slices_ == kMaxSlices) {
-    LOGF(ERROR) << "Over limit of supported slices per frame";
+    VLOGF(1) << "Over limit of supported slices per frame";
     return false;
   }
 
@@ -2228,7 +2243,7 @@
   InputRecord& input_record = input_buffer_map_[index];
 
   if (input_record.bytes_used + size > input_record.length) {
-    DVLOGF(1) << "Input buffer too small";
+    VLOGF(1) << "Input buffer too small";
     return false;
   }
 
@@ -2306,6 +2321,7 @@
     const scoped_refptr<H264Picture>& pic) {
   scoped_refptr<V4L2DecodeSurface> dec_surface =
       H264PictureToV4L2DecodeSurface(pic);
+  dec_surface->set_visible_rect(pic->visible_rect);
   v4l2_dec_->SurfaceReady(dec_surface);
   return true;
 }
@@ -2537,7 +2553,7 @@
     const scoped_refptr<VP8Picture>& pic) {
   scoped_refptr<V4L2DecodeSurface> dec_surface =
       VP8PictureToV4L2DecodeSurface(pic);
-
+  dec_surface->set_visible_rect(pic->visible_rect);
   v4l2_dec_->SurfaceReady(dec_surface);
   return true;
 }
@@ -2840,7 +2856,7 @@
     const scoped_refptr<VP9Picture>& pic) {
   scoped_refptr<V4L2DecodeSurface> dec_surface =
       VP9PictureToV4L2DecodeSurface(pic);
-
+  dec_surface->set_visible_rect(pic->visible_rect);
   v4l2_dec_->SurfaceReady(dec_surface);
   return true;
 }
@@ -2920,13 +2936,13 @@
     const scoped_refptr<V4L2DecodeSurface>& dec_surface) {
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
-  DVLOGF(3) << "Submitting decode for surface: " << dec_surface->ToString();
+  DVLOGF(4) << "Submitting decode for surface: " << dec_surface->ToString();
   Enqueue(dec_surface);
 }
 
 void V4L2SliceVideoDecodeAccelerator::SurfaceReady(
     const scoped_refptr<V4L2DecodeSurface>& dec_surface) {
-  DVLOGF(3);
+  DVLOGF(4);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
 
   decoder_display_queue_.push(dec_surface);
@@ -2964,14 +2980,12 @@
   DCHECK_NE(output_record.picture_id, -1);
   output_record.at_client = true;
 
-  // TODO(posciak): Use visible size from decoder here instead
-  // (crbug.com/402760). Passing (0, 0) results in the client using the
-  // visible size extracted from the container instead.
   Picture picture(output_record.picture_id, dec_surface->bitstream_id(),
-                  Rect(0, 0), false);
-  DVLOGF(3) << dec_surface->ToString()
+                  dec_surface->visible_rect(), true /* allow_overlay */);
+  DVLOGF(4) << dec_surface->ToString()
             << ", bitstream_id: " << picture.bitstream_buffer_id()
-            << ", picture_id: " << picture.picture_buffer_id();
+            << ", picture_id: " << picture.picture_buffer_id()
+            << ", visible_rect: " << picture.visible_rect().ToString();
   pending_picture_ready_.push(PictureRecord(output_record.cleared, picture));
   SendPictureReady();
   output_record.cleared = true;
@@ -3006,9 +3020,10 @@
 }
 
 void V4L2SliceVideoDecodeAccelerator::SendPictureReady() {
-  DVLOGF(3);
+  DVLOGF(4);
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
-  bool resetting_or_flushing = (decoder_resetting_ || decoder_flushing_);
+  bool send_now =
+      (decoder_resetting_ || decoder_flushing_ || surface_set_change_pending_);
   while (!pending_picture_ready_.empty()) {
     bool cleared = pending_picture_ready_.front().cleared;
     const Picture& picture = pending_picture_ready_.front().picture;
@@ -3022,17 +3037,20 @@
           FROM_HERE,
           base::Bind(&Client::PictureReady, decode_client_, picture));
       pending_picture_ready_.pop();
-    } else if (!cleared || resetting_or_flushing) {
-      DVLOGF(3) << "cleared=" << pending_picture_ready_.front().cleared
+    } else if (!cleared || send_now) {
+      DVLOGF(4) << "cleared=" << pending_picture_ready_.front().cleared
                 << ", decoder_resetting_=" << decoder_resetting_
                 << ", decoder_flushing_=" << decoder_flushing_
+                << ", surface_set_change_pending_="
+                << surface_set_change_pending_
                 << ", picture_clearing_count_=" << picture_clearing_count_;
       DVLOGF(4) << "Posting picture ready to GPU for: "
                 << picture.picture_buffer_id();
       // If the picture is not cleared, post it to the child thread because it
       // has to be cleared in the child thread. A picture only needs to be
-      // cleared once. If the decoder is resetting or flushing, send all
-      // pictures to ensure PictureReady arrive before reset or flush done.
+      // cleared once. If the decoder is resetting or flushing or changing
+      // resolution, send all pictures to ensure PictureReady arrive before
+      // reset done, flush done, or picture dismissed.
       child_task_runner_->PostTaskAndReply(
           FROM_HERE, base::Bind(&Client::PictureReady, client_, picture),
           // Unretained is safe. If Client::PictureReady gets to run, |this| is
@@ -3051,7 +3069,7 @@
 }
 
 void V4L2SliceVideoDecodeAccelerator::PictureCleared() {
-  DVLOGF(3) << "clearing count=" << picture_clearing_count_;
+  DVLOGF(4) << "clearing count=" << picture_clearing_count_;
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
   DCHECK_GT(picture_clearing_count_, 0);
   picture_clearing_count_--;
diff --git a/vda/v4l2_slice_video_decode_accelerator.h b/vda/v4l2_slice_video_decode_accelerator.h
index 56d4374..8849625 100644
--- a/vda/v4l2_slice_video_decode_accelerator.h
+++ b/vda/v4l2_slice_video_decode_accelerator.h
@@ -1,6 +1,7 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 85fdf90
 
 #ifndef V4L2_SLICE_VIDEO_DECODE_ACCELERATOR_H_
 #define V4L2_SLICE_VIDEO_DECODE_ACCELERATOR_H_
@@ -47,6 +48,7 @@
   void AssignPictureBuffers(const std::vector<PictureBuffer>& buffers) override;
   void ImportBufferForPicture(
       int32_t picture_buffer_id,
+      VideoPixelFormat pixel_format,
       const NativePixmapHandle& native_pixmap_handle) override;
   void ReusePictureBuffer(int32_t picture_buffer_id) override;
   void Flush() override;
@@ -77,6 +79,7 @@
   // Record for output buffers.
   struct OutputRecord {
     OutputRecord();
+    OutputRecord(OutputRecord&&) = default;
     bool at_device;
     bool at_client;
     int32_t picture_id;
@@ -234,9 +237,9 @@
   // file descriptors.
   void ImportBufferForPictureTask(
       int32_t picture_buffer_id,
-      // TODO(posciak): (crbug.com/561749) we should normally be able to pass
-      // the vector by itself via std::move, but it's not possible to do this
-      // if this method is used as a callback.
+      // TODO(posciak): (https://crbug.com/561749) we should normally be able to
+      // pass the vector by itself via std::move, but it's not possible to do
+      // this if this method is used as a callback.
       std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds);
 
   // Performed on decoder_thread_ as a consequence of poll() on decoder_thread_
@@ -366,7 +369,6 @@
   VideoCodecProfile video_profile_;
   uint32_t input_format_fourcc_;
   uint32_t output_format_fourcc_;
-  Size visible_size_;
   Size coded_size_;
 
   struct BitstreamBufferRef;
@@ -417,6 +419,7 @@
     bool cleared;  // Whether the texture is cleared and safe to render from.
     Picture picture;  // The decoded picture.
   };
+
   // Pictures that are ready but not sent to PictureReady yet.
   std::queue<PictureRecord> pending_picture_ready_;
 
diff --git a/vda/v4l2_video_decode_accelerator.cc b/vda/v4l2_video_decode_accelerator.cc
index 0003688..22a0912 100644
--- a/vda/v4l2_video_decode_accelerator.cc
+++ b/vda/v4l2_video_decode_accelerator.cc
@@ -1,6 +1,8 @@
 // Copyright 2014 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.
+// Note: ported from Chromium commit head: 91175b1
+// Note: image processor is not ported.
 
 #include "v4l2_video_decode_accelerator.h"
 
@@ -28,22 +30,20 @@
 #include "shared_memory_region.h"
 #include "videodev2.h"
 
-#define LOGF(level) LOG(level) << __func__ << "(): "
-#define DLOGF(level) DLOG(level) << __func__ << "(): "
 #define DVLOGF(level) DVLOG(level) << __func__ << "(): "
 #define VLOGF(level) VLOG(level) << __func__ << "(): "
-#define PLOGF(level) PLOG(level) << __func__ << "(): "
+#define VPLOGF(level) VPLOG(level) << __func__ << "(): "
 
-#define NOTIFY_ERROR(x)                         \
-  do {                                          \
-    LOGF(ERROR) << "Setting error state:" << x; \
-    SetErrorState(x);                           \
+#define NOTIFY_ERROR(x)                      \
+  do {                                       \
+    VLOGF(1) << "Setting error state:" << x; \
+    SetErrorState(x);                        \
   } while (0)
 
 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_str) \
   do {                                                          \
     if (device_->Ioctl(type, arg) != 0) {                       \
-      PLOGF(ERROR) << "ioctl() failed: " << type_str;           \
+      VPLOGF(1) << "ioctl() failed: " << type_str;              \
       NOTIFY_ERROR(PLATFORM_FAILURE);                           \
       return value;                                             \
     }                                                           \
@@ -55,10 +55,10 @@
 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \
   IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false, #type)
 
-#define IOCTL_OR_LOG_ERROR(type, arg)              \
-  do {                                             \
-    if (device_->Ioctl(type, arg) != 0)            \
-      PLOGF(ERROR) << "ioctl() failed: " << #type; \
+#define IOCTL_OR_LOG_ERROR(type, arg)           \
+  do {                                          \
+    if (device_->Ioctl(type, arg) != 0)         \
+      VPLOGF(1) << "ioctl() failed: " << #type; \
   } while (0)
 
 namespace media {
@@ -153,6 +153,7 @@
 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() {
   DCHECK(!decoder_thread_.IsRunning());
   DCHECK(!device_poll_thread_.IsRunning());
+  DVLOGF(2);
 
   // These maps have members that should be manually destroyed, e.g. file
   // descriptors, mmap() segments, etc.
@@ -199,8 +200,8 @@
   const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
   IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps);
   if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
-    LOGF(ERROR) << "ioctl() failed: VIDIOC_QUERYCAP"
-                << ", caps check failed: 0x" << std::hex << caps.capabilities;
+    VLOGF(1) << "ioctl() failed: VIDIOC_QUERYCAP"
+             << ", caps check failed: 0x" << std::hex << caps.capabilities;
     return false;
   }
 
@@ -212,7 +213,7 @@
   }
 
   if (!decoder_thread_.Start()) {
-    LOGF(ERROR) << "decoder thread failed to start";
+    VLOGF(1) << "decoder thread failed to start";
     return false;
   }
 
@@ -256,7 +257,7 @@
   DCHECK(decode_task_runner_->BelongsToCurrentThread());
 
   if (bitstream_buffer.id() < 0) {
-    LOGF(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id();
+    VLOGF(1) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id();
     if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle()))
       base::SharedMemory::CloseHandle(bitstream_buffer.handle());
     NOTIFY_ERROR(INVALID_ARGUMENT);
@@ -289,8 +290,8 @@
   uint32_t req_buffer_count = output_dpb_size_ + kDpbOutputBufferExtraCount;
 
   if (buffers.size() < req_buffer_count) {
-    LOGF(ERROR) << "Failed to provide requested picture buffers. (Got "
-                << buffers.size() << ", requested " << req_buffer_count << ")";
+    VLOGF(1) << "Failed to provide requested picture buffers. (Got "
+             << buffers.size() << ", requested " << req_buffer_count << ")";
     NOTIFY_ERROR(INVALID_ARGUMENT);
     return;
   }
@@ -304,7 +305,7 @@
   IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs);
 
   if (reqbufs.count != buffers.size()) {
-    DLOGF(ERROR) << "Could not allocate enough output buffers";
+    VLOGF(1) << "Could not allocate enough output buffers";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return;
   }
@@ -334,22 +335,31 @@
 
 void V4L2VideoDecodeAccelerator::ImportBufferForPicture(
     int32_t picture_buffer_id,
+    VideoPixelFormat pixel_format,
     const NativePixmapHandle& native_pixmap_handle) {
   DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id;
   DCHECK(child_task_runner_->BelongsToCurrentThread());
 
   if (output_mode_ != Config::OutputMode::IMPORT) {
-    LOGF(ERROR) << "Cannot import in non-import mode";
+    VLOGF(1) << "Cannot import in non-import mode";
     NOTIFY_ERROR(INVALID_ARGUMENT);
     return;
   }
+
+  if (pixel_format !=
+      V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_)) {
+    VLOGF(1) << "Unsupported import format: " << pixel_format;
+    NOTIFY_ERROR(INVALID_ARGUMENT);
+    return;
+  }
+
   std::vector<base::ScopedFD> dmabuf_fds;
   for (const auto& fd : native_pixmap_handle.fds) {
     DCHECK_NE(fd.fd, -1);
     dmabuf_fds.push_back(base::ScopedFD(fd.fd));
   }
 
-  decode_task_runner_->PostTask(
+  decoder_thread_.task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&V4L2VideoDecodeAccelerator::ImportBufferForPictureTask,
                  base::Unretained(this), picture_buffer_id,
@@ -379,7 +389,7 @@
   }
 
   if (iter->state != kAtClient) {
-    LOGF(ERROR) << "Cannot import buffer not owned by client";
+    VLOGF(1) << "Cannot import buffer not owned by client";
     NOTIFY_ERROR(INVALID_ARGUMENT);
     return;
   }
@@ -448,6 +458,7 @@
   }
 
   delete this;
+  VLOGF(2) << "Destroyed.";
 }
 
 bool V4L2VideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread(
@@ -489,7 +500,7 @@
     return;
 
   if (!bitstream_record->shm->Map()) {
-    LOGF(ERROR) << "could not map bitstream_buffer";
+    VLOGF(1) << "could not map bitstream_buffer";
     NOTIFY_ERROR(UNREADABLE_INPUT);
     return;
   }
@@ -523,7 +534,7 @@
   decoder_decode_buffer_tasks_scheduled_--;
 
   if (decoder_state_ != kInitialized && decoder_state_ != kDecoding) {
-    VLOGF(2) << "early out: state=" << decoder_state_;
+    DVLOGF(3) << "early out: state=" << decoder_state_;
     return;
   }
 
@@ -729,7 +740,7 @@
 bool V4L2VideoDecodeAccelerator::DecodeBufferInitial(const void* data,
                                                      size_t size,
                                                      size_t* endpos) {
-  DVLOGF(4) << "data=" << data << ", size=" << size;
+  DVLOGF(3) << "data=" << data << ", size=" << size;
   DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
   DCHECK_EQ(decoder_state_, kInitialized);
   // Initial decode.  We haven't been able to get output stream format info yet.
@@ -749,32 +760,21 @@
   // Recycle buffers.
   Dequeue();
 
-  // Check and see if we have format info yet.
-  struct v4l2_format format;
-  Size visible_size;
-  bool again = false;
-  if (!GetFormatInfo(&format, &visible_size, &again))
-    return false;
-
   *endpos = size;
 
-  if (again) {
+  // If an initial resolution change event is not done yet, a driver probably
+  // needs more stream to decode format.
+  // Return true and schedule next buffer without changing status to kDecoding.
+  // If the initial resolution change is done and coded size is known, we may
+  // still have to wait for AssignPictureBuffers() and output buffers to be
+  // allocated.
+  if (coded_size_.IsEmpty() || output_buffer_map_.empty()) {
     // Need more stream to decode format, return true and schedule next buffer.
     return true;
   }
 
-  // Run this initialization only on first startup.
-  if (output_buffer_map_.empty()) {
-    DVLOGF(4) << "running initialization";
-    // Success! Setup our parameters.
-    if (!CreateBuffersForFormat(format, visible_size))
-      return false;
-    // We are waiting for AssignPictureBuffers. Do not set the state to
-    // kDecoding.
-  } else {
-    decoder_state_ = kDecoding;
-    ScheduleDecodeBufferTaskIfNeeded();
-  }
+  decoder_state_ = kDecoding;
+  ScheduleDecodeBufferTaskIfNeeded();
   return true;
 }
 
@@ -818,7 +818,7 @@
       Dequeue();
       if (free_input_buffers_.empty()) {
         // Nope!
-        DVLOGF(3) << "stalled for input buffers";
+        DVLOGF(4) << "stalled for input buffers";
         return false;
       }
     }
@@ -843,7 +843,7 @@
   // Copy in to the buffer.
   InputRecord& input_record = input_buffer_map_[decoder_current_input_buffer_];
   if (size > input_record.length - input_record.bytes_used) {
-    LOGF(ERROR) << "over-size frame, erroring";
+    VLOGF(1) << "over-size frame, erroring";
     NOTIFY_ERROR(UNREADABLE_INPUT);
     return false;
   }
@@ -892,7 +892,7 @@
 }
 
 void V4L2VideoDecodeAccelerator::ServiceDeviceTask(bool event_pending) {
-  DVLOGF(3);
+  DVLOGF(4);
   DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
   DCHECK_NE(decoder_state_, kUninitialized);
   TRACE_EVENT0("Video Decoder", "V4L2VDA::ServiceDeviceTask");
@@ -911,6 +911,25 @@
   bool resolution_change_pending = false;
   if (event_pending)
     resolution_change_pending = DequeueResolutionChangeEvent();
+
+  if (!resolution_change_pending && coded_size_.IsEmpty()) {
+    // Some platforms do not send an initial resolution change event.
+    // To work around this, we need to keep checking if the initial resolution
+    // is known already by explicitly querying the format after each decode,
+    // regardless of whether we received an event.
+    // This needs to be done on initial resolution change,
+    // i.e. when coded_size_.IsEmpty().
+
+    // Try GetFormatInfo to check if an initial resolution change can be done.
+    struct v4l2_format format;
+    Size visible_size;
+    bool again;
+    if (GetFormatInfo(&format, &visible_size, &again) && !again) {
+      resolution_change_pending = true;
+      DequeueResolutionChangeEvent();
+    }
+  }
+
   Dequeue();
   Enqueue();
 
@@ -938,16 +957,16 @@
       FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::DevicePollTask,
                             base::Unretained(this), poll_device));
 
-  DVLOG(3) << "ServiceDeviceTask(): buffer counts: DEC["
-           << decoder_input_queue_.size() << "->"
-           << input_ready_queue_.size() << "] => DEVICE["
-           << free_input_buffers_.size() << "+"
-           << input_buffer_queued_count_ << "/"
-           << input_buffer_map_.size() << "->"
-           << free_output_buffers_.size() << "+"
-           << output_buffer_queued_count_ << "/"
-           << output_buffer_map_.size() << "] => CLIENT["
-           << decoder_frames_at_client_ << "]";
+  DVLOGF(3) << "ServiceDeviceTask(): buffer counts: DEC["
+            << decoder_input_queue_.size() << "->"
+            << input_ready_queue_.size() << "] => DEVICE["
+            << free_input_buffers_.size() << "+"
+            << input_buffer_queued_count_ << "/"
+            << input_buffer_map_.size() << "->"
+            << free_output_buffers_.size() << "+"
+            << output_buffer_queued_count_ << "/"
+            << output_buffer_map_.size() << "] => CLIENT["
+            << decoder_frames_at_client_ << "]";
 
   ScheduleDecodeBufferTaskIfNeeded();
   if (resolution_change_pending)
@@ -992,7 +1011,7 @@
     // We just started up a previously empty queue.
     // Queue state changed; signal interrupt.
     if (!device_->SetDevicePollInterrupt()) {
-      PLOGF(ERROR) << "SetDevicePollInterrupt failed";
+      VPLOGF(1) << "SetDevicePollInterrupt failed";
       NOTIFY_ERROR(PLATFORM_FAILURE);
       return;
     }
@@ -1014,7 +1033,7 @@
     // We just started up a previously empty queue.
     // Queue state changed; signal interrupt.
     if (!device_->SetDevicePollInterrupt()) {
-      PLOGF(ERROR) << "SetDevicePollInterrupt(): failed";
+      VPLOGF(1) << "SetDevicePollInterrupt(): failed";
       NOTIFY_ERROR(PLATFORM_FAILURE);
       return;
     }
@@ -1042,8 +1061,7 @@
         return true;
       }
     } else {
-      LOGF(ERROR) << "got an event (" << ev.type
-                  << ") we haven't subscribed to.";
+      VLOGF(1) << "got an event (" << ev.type << ") we haven't subscribed to.";
     }
   }
   return false;
@@ -1086,7 +1104,7 @@
       // EAGAIN if we're just out of buffers to dequeue.
       return false;
     }
-    PLOGF(ERROR) << "ioctl() failed: VIDIOC_DQBUF";
+    VPLOGF(1) << "ioctl() failed: VIDIOC_DQBUF";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return false;
   }
@@ -1125,7 +1143,7 @@
       DVLOGF(3) << "Got EPIPE. Last output buffer was already dequeued.";
       return false;
     }
-    PLOGF(ERROR) << "ioctl() failed: VIDIOC_DQBUF";
+    VPLOGF(1) << "ioctl() failed: VIDIOC_DQBUF";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return false;
   }
@@ -1248,14 +1266,14 @@
     // posted to us by the client. In that case just ignore this (we've already
     // dismissed it and accounted for that) and let the sync object get
     // destroyed.
-    DVLOGF(4) << "got picture id= " << picture_buffer_id
+    DVLOGF(3) << "got picture id= " << picture_buffer_id
               << " not in use (anymore?).";
     return;
   }
 
   OutputRecord& output_record = output_buffer_map_[index];
   if (output_record.state != kAtClient) {
-    LOGF(ERROR) << "picture_buffer_id not reusable";
+    VLOGF(1) << "picture_buffer_id not reusable";
     NOTIFY_ERROR(INVALID_ARGUMENT);
     return;
   }
@@ -1272,14 +1290,7 @@
   DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
   TRACE_EVENT0("Video Decoder", "V4L2VDA::FlushTask");
 
-  // Flush outstanding buffers.
-  if (decoder_state_ == kInitialized) {
-    // There's nothing in the pipe, so return done immediately.
-    VLOGF(2) << "returning flush";
-    child_task_runner_->PostTask(FROM_HERE,
-                                 base::Bind(&Client::NotifyFlushDone, client_));
-    return;
-  } else if (decoder_state_ == kError) {
+  if (decoder_state_ == kError) {
     VLOGF(2) << "early out: kError state";
     return;
   }
@@ -1328,10 +1339,10 @@
     return;
   }
 
-  // TODO(posciak): crbug.com/270039. Exynos requires a streamoff-streamon
-  // sequence after flush to continue, even if we are not resetting. This would
-  // make sense, because we don't really want to resume from a non-resume point
-  // (e.g. not from an IDR) if we are flushed.
+  // TODO(posciak): https://crbug.com/270039. Exynos requires a
+  // streamoff-streamon sequence after flush to continue, even if we are not
+  // resetting. This would make sense, because we don't really want to resume
+  // from a non-resume point (e.g. not from an IDR) if we are flushed.
   // MSE player however triggers a Flush() on chunk end, but never Reset(). One
   // could argue either way, or even say that Flush() is not needed/harmful when
   // transitioning to next chunk.
@@ -1361,7 +1372,7 @@
   memset(&cmd, 0, sizeof(cmd));
   cmd.cmd = V4L2_DEC_CMD_STOP;
   if (device_->Ioctl(VIDIOC_TRY_DECODER_CMD, &cmd) != 0) {
-    DVLOGF(3) "V4L2_DEC_CMD_STOP is not supported.";
+    VLOGF(2) << "V4L2_DEC_CMD_STOP is not supported.";
     return false;
   }
 
@@ -1512,7 +1523,7 @@
 
   // Start up the device poll thread and schedule its first DevicePollTask().
   if (!device_poll_thread_.Start()) {
-    LOGF(ERROR) << "Device thread failed to start";
+    VLOGF(1) << "Device thread failed to start";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return false;
   }
@@ -1534,7 +1545,7 @@
 
   // Signal the DevicePollTask() to stop, and stop the device poll thread.
   if (!device_->SetDevicePollInterrupt()) {
-    PLOGF(ERROR) << "SetDevicePollInterrupt(): failed";
+    VPLOGF(1) << "SetDevicePollInterrupt(): failed";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return false;
   }
@@ -1612,7 +1623,7 @@
   SendPictureReady();  // Send all pending PictureReady.
 
   if (!DestroyOutputBuffers()) {
-    LOGF(ERROR) << "Failed destroying output buffers.";
+    VLOGF(1) << "Failed destroying output buffers.";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return;
   }
@@ -1635,13 +1646,13 @@
   Size visible_size;
   bool ret = GetFormatInfo(&format, &visible_size, &again);
   if (!ret || again) {
-    LOGF(ERROR) << "Couldn't get format information after resolution change";
+    VLOGF(1) << "Couldn't get format information after resolution change";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return;
   }
 
   if (!CreateBuffersForFormat(format, visible_size)) {
-    LOGF(ERROR) << "Couldn't reallocate buffers after resolution change";
+    VLOGF(1) << "Couldn't reallocate buffers after resolution change";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return;
   }
@@ -1670,7 +1681,7 @@
 }
 
 void V4L2VideoDecodeAccelerator::NotifyError(Error error) {
-  VLOGF(2);
+  VLOGF(1);
 
   if (!child_task_runner_->BelongsToCurrentThread()) {
     child_task_runner_->PostTask(
@@ -1718,7 +1729,7 @@
       *again = true;
       return true;
     } else {
-      PLOGF(ERROR) << "ioctl() failed: VIDIOC_G_FMT";
+      VPLOGF(1) << "ioctl() failed: VIDIOC_G_FMT";
       NOTIFY_ERROR(PLATFORM_FAILURE);
       return false;
     }
@@ -1726,7 +1737,7 @@
 
   // Make sure we are still getting the format we set on initialization.
   if (format->fmt.pix_mp.pixelformat != output_format_fourcc_) {
-    LOGF(ERROR) << "Unexpected format from G_FMT on output";
+    VLOGF(1) << "Unexpected format from G_FMT on output";
     return false;
   }
 
@@ -1763,16 +1774,16 @@
   selection_arg.target = V4L2_SEL_TGT_COMPOSE;
 
   if (device_->Ioctl(VIDIOC_G_SELECTION, &selection_arg) == 0) {
-    DVLOGF(2) << "VIDIOC_G_SELECTION is supported";
+    VLOGF(2) << "VIDIOC_G_SELECTION is supported";
     visible_rect = &selection_arg.r;
   } else {
-    DVLOGF(2) << "Fallback to VIDIOC_G_CROP";
+    VLOGF(2) << "Fallback to VIDIOC_G_CROP";
     struct v4l2_crop crop_arg;
     memset(&crop_arg, 0, sizeof(crop_arg));
     crop_arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 
     if (device_->Ioctl(VIDIOC_G_CROP, &crop_arg) != 0) {
-      PLOGF(ERROR) << "ioctl() VIDIOC_G_CROP failed";
+      VPLOGF(1) << "ioctl() VIDIOC_G_CROP failed";
       return coded_size;
     }
     visible_rect = &crop_arg.c;
@@ -1782,19 +1793,19 @@
             visible_rect->height);
   VLOGF(2) << "visible rectangle is " << rect.ToString();
   if (!Rect(coded_size).Contains(rect)) {
-    DLOGF(ERROR) << "visible rectangle " << rect.ToString()
-                 << " is not inside coded size " << coded_size.ToString();
+    DVLOGF(3) << "visible rectangle " << rect.ToString()
+              << " is not inside coded size " << coded_size.ToString();
     return coded_size;
   }
   if (rect.IsEmpty()) {
-    DLOGF(ERROR) << "visible size is empty";
+    VLOGF(1) << "visible size is empty";
     return coded_size;
   }
 
   // Chrome assume picture frame is coded at (0, 0).
   if (rect.x() != 0 || rect.y() != 0) {
-    DLOGF(ERROR) << "Unexpected visible rectangle " << rect.ToString()
-                 << ", top-left is not origin";
+    VLOGF(1) << "Unexpected visible rectangle " << rect.ToString()
+             << ", top-left is not origin";
     return coded_size;
   }
 
@@ -1836,7 +1847,7 @@
                                   MAP_SHARED,
                                   buffer.m.planes[0].m.mem_offset);
     if (address == MAP_FAILED) {
-      PLOGF(ERROR) << "mmap() failed";
+      VPLOGF(1) << "mmap() failed";
       return false;
     }
     input_buffer_map_[i].address = address;
@@ -1913,7 +1924,7 @@
   }
 
   if (output_format_fourcc_ == 0) {
-    VLOGF(1) << "Image processor not available";
+    VLOGF(2) << "Image processor not available";
     return false;
   }
   VLOGF(2) << "Output format=" << output_format_fourcc_;
@@ -2020,7 +2031,7 @@
   reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
   reqbufs.memory = V4L2_MEMORY_MMAP;
   if (device_->Ioctl(VIDIOC_REQBUFS, &reqbufs) != 0) {
-    PLOGF(ERROR) << "ioctl() failed: VIDIOC_REQBUFS";
+    VPLOGF(1) << "ioctl() failed: VIDIOC_REQBUFS";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     success = false;
   }
diff --git a/vda/v4l2_video_decode_accelerator.h b/vda/v4l2_video_decode_accelerator.h
index 9377043..e18cab4 100644
--- a/vda/v4l2_video_decode_accelerator.h
+++ b/vda/v4l2_video_decode_accelerator.h
@@ -5,6 +5,8 @@
 // This file contains an implementation of VideoDecodeAccelerator
 // that utilizes hardware video decoders, which expose Video4Linux 2 API
 // (http://linuxtv.org/downloads/v4l-dvb-apis/).
+// Note: ported from Chromium commit head: 85fdf90
+// Note: image processor is not ported.
 
 #ifndef MEDIA_GPU_V4L2_VIDEO_DECODE_ACCELERATOR_H_
 #define MEDIA_GPU_V4L2_VIDEO_DECODE_ACCELERATOR_H_
@@ -93,6 +95,7 @@
   void AssignPictureBuffers(const std::vector<PictureBuffer>& buffers) override;
   void ImportBufferForPicture(
       int32_t picture_buffer_id,
+      VideoPixelFormat pixel_format,
       const NativePixmapHandle& native_pixmap_handle) override;
   void ReusePictureBuffer(int32_t picture_buffer_id) override;
   void Flush() override;
diff --git a/vda/video_codecs.cc b/vda/video_codecs.cc
index 995ee38..61d0708 100644
--- a/vda/video_codecs.cc
+++ b/vda/video_codecs.cc
@@ -1,6 +1,8 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: b03fc92
+// Note: only necessary functions are ported.
 
 #include "video_codecs.h"
 
diff --git a/vda/video_codecs.h b/vda/video_codecs.h
index 30df7ec..2c88d50 100644
--- a/vda/video_codecs.h
+++ b/vda/video_codecs.h
@@ -1,6 +1,8 @@
 // Copyright 2012 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.
+// Note: ported from Chromium commit head: b03fc92
+// Note: only necessary functions are ported.
 
 #ifndef VIDEO_CODECS_H_
 #define VIDEO_CODECS_H_
diff --git a/vda/video_decode_accelerator.cc b/vda/video_decode_accelerator.cc
index cee4dcc..e74d1ec 100644
--- a/vda/video_decode_accelerator.cc
+++ b/vda/video_decode_accelerator.cc
@@ -1,6 +1,7 @@
 // Copyright (c) 2011 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.
+// Note: ported from Chromium commit head: 85fdf90
 
 #include "base/logging.h"
 
@@ -27,7 +28,7 @@
   NOTREACHED() << "By default deferred initialization is not supported.";
 }
 
-VideoDecodeAccelerator::~VideoDecodeAccelerator() {}
+VideoDecodeAccelerator::~VideoDecodeAccelerator() = default;
 
 bool VideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread(
     const base::WeakPtr<Client>& decode_client,
@@ -39,6 +40,7 @@
 
 void VideoDecodeAccelerator::ImportBufferForPicture(
     int32_t picture_buffer_id,
+    VideoPixelFormat pixel_format,
     const NativePixmapHandle& native_pixmap_handle) {
   NOTREACHED() << "Buffer import not supported.";
 }
@@ -46,14 +48,14 @@
 VideoDecodeAccelerator::SupportedProfile::SupportedProfile()
     : profile(VIDEO_CODEC_PROFILE_UNKNOWN), encrypted_only(false) {}
 
-VideoDecodeAccelerator::SupportedProfile::~SupportedProfile() {}
+VideoDecodeAccelerator::SupportedProfile::~SupportedProfile() = default;
 
 VideoDecodeAccelerator::Capabilities::Capabilities() : flags(NO_FLAGS) {}
 
 VideoDecodeAccelerator::Capabilities::Capabilities(const Capabilities& other) =
     default;
 
-VideoDecodeAccelerator::Capabilities::~Capabilities() {}
+VideoDecodeAccelerator::Capabilities::~Capabilities() = default;
 
 std::string VideoDecodeAccelerator::Capabilities::AsHumanReadableString()
     const {
diff --git a/vda/video_decode_accelerator.h b/vda/video_decode_accelerator.h
index 6834570..10601be 100644
--- a/vda/video_decode_accelerator.h
+++ b/vda/video_decode_accelerator.h
@@ -1,6 +1,7 @@
 // Copyright (c) 2012 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.
+// Note: ported from Chromium commit head: 85fdf90
 
 #ifndef VIDEO_DECODE_ACCELERATOR_H_
 #define VIDEO_DECODE_ACCELERATOR_H_
@@ -245,15 +246,20 @@
   virtual void AssignPictureBuffers(
       const std::vector<PictureBuffer>& buffers) = 0;
 
-  // Imports |native_pixmap_handle| as backing memory for picture buffer
-  // associated with |picture_buffer_id|. This can only be be used if the VDA
-  // has been Initialize()d with config.output_mode = IMPORT, and should be
-  // preceded by a call to AssignPictureBuffers() to set up the number of
-  // PictureBuffers and their details.
+  // Imports |gpu_memory_buffer_handle|, pointing to a buffer in |pixel_format|,
+  // as backing memory for picture buffer associated with |picture_buffer_id|.
+  // This can only be be used if the VDA has been Initialize()d with
+  // config.output_mode = IMPORT, and should be preceded by a call to
+  // AssignPictureBuffers() to set up the number of PictureBuffers and their
+  // details.
+  // The |pixel_format| used here may be different from the |pixel_format|
+  // required in ProvidePictureBuffers(). If the buffer cannot be imported an
+  // error should be notified via NotifyError().
   // After this call, the VDA becomes the owner of those file descriptors,
   // and is responsible for closing it after use, also on import failure.
   virtual void ImportBufferForPicture(
       int32_t picture_buffer_id,
+      VideoPixelFormat pixel_format,
       const NativePixmapHandle& native_pixmap_handle);
 
   // Sends picture buffers to be reused by the decoder. This needs to be called
diff --git a/vda/video_pixel_format.h b/vda/video_pixel_format.h
index d593dad..7f75cc4 100644
--- a/vda/video_pixel_format.h
+++ b/vda/video_pixel_format.h
@@ -1,6 +1,8 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 006301b
+// Note: only necessary functions are ported from video_types.h
 
 #ifndef VIDEO_PIXEL_FORMAT_H_
 #define VIDEO_PIXEL_FORMAT_H_
@@ -15,10 +17,14 @@
   PIXEL_FORMAT_UNKNOWN = 0,  // Unknown or unspecified format value.
   PIXEL_FORMAT_I420 =
       1,  // 12bpp YUV planar 1x1 Y, 2x2 UV samples, a.k.a. YU12.
-  PIXEL_FORMAT_YV12 = 2,   // 12bpp YVU planar 1x1 Y, 2x2 VU samples.
-  PIXEL_FORMAT_YV16 = 3,   // 16bpp YVU planar 1x1 Y, 2x1 VU samples.
-  PIXEL_FORMAT_YV12A = 4,  // 20bpp YUVA planar 1x1 Y, 2x2 VU, 1x1 A samples.
-  PIXEL_FORMAT_YV24 = 5,   // 24bpp YUV planar, no subsampling.
+
+  // Note: Chrome does not actually support YVU compositing, so you probably
+  // don't actually want to use this. See http://crbug.com/784627.
+  PIXEL_FORMAT_YV12 = 2,  // 12bpp YVU planar 1x1 Y, 2x2 VU samples.
+
+  PIXEL_FORMAT_I422 = 3,   // 16bpp YUV planar 1x1 Y, 2x1 UV samples.
+  PIXEL_FORMAT_I420A = 4,  // 20bpp YUVA planar 1x1 Y, 2x2 UV, 1x1 A samples.
+  PIXEL_FORMAT_I444 = 5,   // 24bpp YUV planar, no subsampling.
   PIXEL_FORMAT_NV12 =
       6,  // 12bpp with Y plane followed by a 2x2 interleaved UV plane.
   PIXEL_FORMAT_NV21 =
@@ -42,6 +48,8 @@
   // Plane size = Row pitch * (((height+31)/32)*32)
   PIXEL_FORMAT_MT21 = 15,
 
+  // The P* in the formats below designates the number of bits per pixel. I.e.
+  // P9 is 9-bits per pixel, P10 is 10-bits per pixel, etc.
   PIXEL_FORMAT_YUV420P9 = 16,
   PIXEL_FORMAT_YUV420P10 = 17,
   PIXEL_FORMAT_YUV422P9 = 18,
@@ -53,15 +61,12 @@
   PIXEL_FORMAT_YUV422P12 = 23,
   PIXEL_FORMAT_YUV444P12 = 24,
 
-  PIXEL_FORMAT_Y8 = 25,   // single 8bpp plane.
+  /* PIXEL_FORMAT_Y8 = 25, Deprecated */
   PIXEL_FORMAT_Y16 = 26,  // single 16bpp plane.
 
-  PIXEL_FORMAT_I422 =
-      27,  // 16bpp YUV planar 1x1 Y, 2x1 UV samples, a.k.a. YU16.
-
   // Please update UMA histogram enumeration when adding new formats here.
   PIXEL_FORMAT_MAX =
-      PIXEL_FORMAT_I422,  // Must always be equal to largest entry logged.
+      PIXEL_FORMAT_Y16,  // Must always be equal to largest entry logged.
 };
 
 }  // namespace media
diff --git a/vda/vp8_bool_decoder.cc b/vda/vp8_bool_decoder.cc
index 1d74ced..68f06d0 100644
--- a/vda/vp8_bool_decoder.cc
+++ b/vda/vp8_bool_decoder.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
+// Note: ported from Chromium commit head: 9b6f429
 
 /*
  * Copyright (c) 2010, The WebM Project authors. All rights reserved.
diff --git a/vda/vp8_bool_decoder.h b/vda/vp8_bool_decoder.h
index 445fd68..4b8e3a5 100644
--- a/vda/vp8_bool_decoder.h
+++ b/vda/vp8_bool_decoder.h
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
+// Note: ported from Chromium commit head: 1323b9c
 
 /*
  * Copyright (c) 2010, The WebM Project authors. All rights reserved.
diff --git a/vda/vp8_decoder.cc b/vda/vp8_decoder.cc
index d9ee6e4..cd2d58b 100644
--- a/vda/vp8_decoder.cc
+++ b/vda/vp8_decoder.cc
@@ -1,6 +1,7 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 7441087
 
 #include "vp8_decoder.h"
 
@@ -93,6 +94,7 @@
   if (!curr_pic_)
     return kRanOutOfSurfaces;
 
+  curr_pic_->visible_rect = Rect(pic_size_);
   if (!DecodeAndOutputCurrentFrame())
     return kDecodeError;
 
diff --git a/vda/vp8_decoder.h b/vda/vp8_decoder.h
index 653da40..58211f6 100644
--- a/vda/vp8_decoder.h
+++ b/vda/vp8_decoder.h
@@ -1,6 +1,7 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 60f9667
 
 #ifndef VP8_DECODER_H_
 #define VP8_DECODER_H_
diff --git a/vda/vp8_parser.cc b/vda/vp8_parser.cc
index 46eb669..5367545 100644
--- a/vda/vp8_parser.cc
+++ b/vda/vp8_parser.cc
@@ -4,6 +4,8 @@
 //
 // This file contains an implementation of a VP8 raw stream parser,
 // as defined in RFC 6386.
+// Note: ported from Chromium commit head: 2de6929
+
 
 #include "base/logging.h"
 #include "vp8_parser.h"
@@ -51,8 +53,7 @@
 Vp8Parser::Vp8Parser() : stream_(nullptr), bytes_left_(0) {
 }
 
-Vp8Parser::~Vp8Parser() {
-}
+Vp8Parser::~Vp8Parser() = default;
 
 bool Vp8Parser::ParseFrame(const uint8_t* ptr,
                            size_t frame_size,
diff --git a/vda/vp8_parser.h b/vda/vp8_parser.h
index ef9326c..c75e6cc 100644
--- a/vda/vp8_parser.h
+++ b/vda/vp8_parser.h
@@ -4,6 +4,7 @@
 //
 // This file contains an implementation of a VP8 raw stream parser,
 // as defined in RFC 6386.
+// Note: ported from Chromium commit head: 1323b9c
 
 #ifndef VP8_PARSER_H_
 #define VP8_PARSER_H_
diff --git a/vda/vp8_picture.cc b/vda/vp8_picture.cc
index 59938aa..b9030ce 100644
--- a/vda/vp8_picture.cc
+++ b/vda/vp8_picture.cc
@@ -1,6 +1,7 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 6e70beb
 
 #include "vp8_picture.h"
 
diff --git a/vda/vp8_picture.h b/vda/vp8_picture.h
index eb253a4..bd04ec7 100644
--- a/vda/vp8_picture.h
+++ b/vda/vp8_picture.h
@@ -1,25 +1,30 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 70340ce
 
 #ifndef VP8_PICTURE_H_
 #define VP8_PICTURE_H_
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "rect.h"
 
 namespace media {
 
 class V4L2VP8Picture;
 
-class VP8Picture : public base::RefCounted<VP8Picture> {
+class VP8Picture : public base::RefCountedThreadSafe<VP8Picture> {
  public:
   VP8Picture();
 
   virtual V4L2VP8Picture* AsV4L2VP8Picture();
 
+  // The visible size of picture.
+  Rect visible_rect;
+
  protected:
-  friend class base::RefCounted<VP8Picture>;
+  friend class base::RefCountedThreadSafe<VP8Picture>;
   virtual ~VP8Picture();
 
   DISALLOW_COPY_AND_ASSIGN(VP8Picture);
diff --git a/vda/vp9_bool_decoder.cc b/vda/vp9_bool_decoder.cc
index bf227b2..1d2b6f4 100644
--- a/vda/vp9_bool_decoder.cc
+++ b/vda/vp9_bool_decoder.cc
@@ -1,6 +1,7 @@
 // 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.
+// Note: ported from Chromium commit head: 1323b9c
 
 #include "vp9_bool_decoder.h"
 
@@ -35,9 +36,9 @@
 };
 }  // namespace
 
-Vp9BoolDecoder::Vp9BoolDecoder() {}
+Vp9BoolDecoder::Vp9BoolDecoder() = default;
 
-Vp9BoolDecoder::~Vp9BoolDecoder() {}
+Vp9BoolDecoder::~Vp9BoolDecoder() = default;
 
 // 9.2.1 Initialization process for Boolean decoder
 bool Vp9BoolDecoder::Initialize(const uint8_t* data, size_t size) {
diff --git a/vda/vp9_bool_decoder.h b/vda/vp9_bool_decoder.h
index 3862e51..50c386f 100644
--- a/vda/vp9_bool_decoder.h
+++ b/vda/vp9_bool_decoder.h
@@ -1,6 +1,7 @@
 // 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.
+// Note: ported from Chromium commit head: e5a9a62
 
 #ifndef VP9_BOOL_DECODER_H_
 #define VP9_BOOL_DECODER_H_
diff --git a/vda/vp9_compressed_header_parser.cc b/vda/vp9_compressed_header_parser.cc
index d5ee772..524472f 100644
--- a/vda/vp9_compressed_header_parser.cc
+++ b/vda/vp9_compressed_header_parser.cc
@@ -1,6 +1,7 @@
 // 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.
+// Note: ported from Chromium commit head: 2de6929
 
 #include "vp9_compressed_header_parser.h"
 
@@ -59,7 +60,7 @@
 
 }  // namespace
 
-Vp9CompressedHeaderParser::Vp9CompressedHeaderParser() {}
+Vp9CompressedHeaderParser::Vp9CompressedHeaderParser() = default;
 
 // 6.3.1 Tx mode syntax
 void Vp9CompressedHeaderParser::ReadTxMode(Vp9FrameHeader* fhdr) {
diff --git a/vda/vp9_compressed_header_parser.h b/vda/vp9_compressed_header_parser.h
index 032a880..5f5ff56 100644
--- a/vda/vp9_compressed_header_parser.h
+++ b/vda/vp9_compressed_header_parser.h
@@ -1,6 +1,7 @@
 // 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.
+// Note: ported from Chromium commit head: e5a9a62
 
 #ifndef VP9_COMPRESSED_HEADER_PARSER_H_
 #define VP9_COMPRESSED_HEADER_PARSER_H_
diff --git a/vda/vp9_decoder.cc b/vda/vp9_decoder.cc
index 2ea6d16..d8af03d 100644
--- a/vda/vp9_decoder.cc
+++ b/vda/vp9_decoder.cc
@@ -1,7 +1,9 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 7441087
 
+#include "rect.h"
 #include "vp9_decoder.h"
 
 #include <memory>
@@ -136,6 +138,18 @@
     if (!pic)
       return kRanOutOfSurfaces;
 
+    Rect new_render_rect(curr_frame_hdr_->render_width,
+                         curr_frame_hdr_->render_height);
+    // For safety, check the validity of render size or leave it as (0, 0).
+    if (!Rect(pic_size_).Contains(new_render_rect)) {
+      DVLOG(1) << "Render size exceeds picture size. render size: "
+               << new_render_rect.ToString()
+               << ", picture size: " << pic_size_.ToString();
+      new_render_rect = Rect();
+    }
+    DVLOG(2) << "Render resolution: " << new_render_rect.ToString();
+
+    pic->visible_rect = new_render_rect;
     pic->frame_hdr.reset(curr_frame_hdr_.release());
 
     if (!DecodeAndOutputPicture(pic)) {
diff --git a/vda/vp9_decoder.h b/vda/vp9_decoder.h
index 77a8d88..cdbcd69 100644
--- a/vda/vp9_decoder.h
+++ b/vda/vp9_decoder.h
@@ -1,6 +1,7 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 77118c9
 
 #ifndef VP9_DECODER_H_
 #define VP9_DECODER_H_
diff --git a/vda/vp9_parser.cc b/vda/vp9_parser.cc
index de51c7b..bbd90b9 100644
--- a/vda/vp9_parser.cc
+++ b/vda/vp9_parser.cc
@@ -8,6 +8,7 @@
 //  1 something wrong in bitstream
 //  2 parsing steps
 //  3 parsed values (selected)
+// Note: ported from Chromium commit head: 2de6929
 
 #include "vp9_parser.h"
 
@@ -22,6 +23,133 @@
 
 namespace media {
 
+namespace {
+
+// Coefficients extracted verbatim from "VP9 Bitstream & Decoding Process
+// Specification" Version 0.6, Sec 8.6.1 Dequantization functions, see:
+// https://www.webmproject.org/vp9/#draft-vp9-bitstream-and-decoding-process-specification
+constexpr size_t kQIndexRange = 256;
+// clang-format off
+// libva is the only user of high bit depth VP9 formats and only supports
+// 10 bits per component, see https://github.com/01org/libva/issues/137.
+// TODO(mcasas): Add the 12 bit versions of these tables.
+const int16_t kDcQLookup[][kQIndexRange] = {
+    {
+        4,    8,    8,    9,    10,   11,   12,   12,  13,   14,   15,   16,
+        17,   18,   19,   19,   20,   21,   22,   23,  24,   25,   26,   26,
+        27,   28,   29,   30,   31,   32,   32,   33,  34,   35,   36,   37,
+        38,   38,   39,   40,   41,   42,   43,   43,  44,   45,   46,   47,
+        48,   48,   49,   50,   51,   52,   53,   53,  54,   55,   56,   57,
+        57,   58,   59,   60,   61,   62,   62,   63,  64,   65,   66,   66,
+        67,   68,   69,   70,   70,   71,   72,   73,  74,   74,   75,   76,
+        77,   78,   78,   79,   80,   81,   81,   82,  83,   84,   85,   85,
+        87,   88,   90,   92,   93,   95,   96,   98,  99,   101,  102,  104,
+        105,  107,  108,  110,  111,  113,  114,  116, 117,  118,  120,  121,
+        123,  125,  127,  129,  131,  134,  136,  138, 140,  142,  144,  146,
+        148,  150,  152,  154,  156,  158,  161,  164, 166,  169,  172,  174,
+        177,  180,  182,  185,  187,  190,  192,  195, 199,  202,  205,  208,
+        211,  214,  217,  220,  223,  226,  230,  233, 237,  240,  243,  247,
+        250,  253,  257,  261,  265,  269,  272,  276, 280,  284,  288,  292,
+        296,  300,  304,  309,  313,  317,  322,  326, 330,  335,  340,  344,
+        349,  354,  359,  364,  369,  374,  379,  384, 389,  395,  400,  406,
+        411,  417,  423,  429,  435,  441,  447,  454, 461,  467,  475,  482,
+        489,  497,  505,  513,  522,  530,  539,  549, 559,  569,  579,  590,
+        602,  614,  626,  640,  654,  668,  684,  700, 717,  736,  755,  775,
+        796,  819,  843,  869,  896,  925,  955,  988, 1022, 1058, 1098, 1139,
+        1184, 1232, 1282, 1336,
+    },
+    {
+        4,    9,    10,   13,   15,   17,   20,   22,   25,   28,   31,   34,
+        37,   40,   43,   47,   50,   53,   57,   60,   64,   68,   71,   75,
+        78,   82,   86,   90,   93,   97,   101,  105,  109,  113,  116,  120,
+        124,  128,  132,  136,  140,  143,  147,  151,  155,  159,  163,  166,
+        170,  174,  178,  182,  185,  189,  193,  197,  200,  204,  208,  212,
+        215,  219,  223,  226,  230,  233,  237,  241,  244,  248,  251,  255,
+        259,  262,  266,  269,  273,  276,  280,  283,  287,  290,  293,  297,
+        300,  304,  307,  310,  314,  317,  321,  324,  327,  331,  334,  337,
+        343,  350,  356,  362,  369,  375,  381,  387,  394,  400,  406,  412,
+        418,  424,  430,  436,  442,  448,  454,  460,  466,  472,  478,  484,
+        490,  499,  507,  516,  525,  533,  542,  550,  559,  567,  576,  584,
+        592,  601,  609,  617,  625,  634,  644,  655,  666,  676,  687,  698,
+        708,  718,  729,  739,  749,  759,  770,  782,  795,  807,  819,  831,
+        844,  856,  868,  880,  891,  906,  920,  933,  947,  961,  975,  988,
+        1001, 1015, 1030, 1045, 1061, 1076, 1090, 1105, 1120, 1137, 1153, 1170,
+        1186, 1202, 1218, 1236, 1253, 1271, 1288, 1306, 1323, 1342, 1361, 1379,
+        1398, 1416, 1436, 1456, 1476, 1496, 1516, 1537, 1559, 1580, 1601, 1624,
+        1647, 1670, 1692, 1717, 1741, 1766, 1791, 1817, 1844, 1871, 1900, 1929,
+        1958, 1990, 2021, 2054, 2088, 2123, 2159, 2197, 2236, 2276, 2319, 2363,
+        2410, 2458, 2508, 2561, 2616, 2675, 2737, 2802, 2871, 2944, 3020, 3102,
+        3188, 3280, 3375, 3478, 3586, 3702, 3823, 3953, 4089, 4236, 4394, 4559,
+        4737, 4929, 5130, 5347
+   }
+};
+
+const int16_t kAcQLookup[][kQIndexRange] = {
+    {
+        4,    8,    9,    10,   11,   12,   13,   14,   15,   16,   17,   18,
+        19,   20,   21,   22,   23,   24,   25,   26,   27,   28,   29,   30,
+        31,   32,   33,   34,   35,   36,   37,   38,   39,   40,   41,   42,
+        43,   44,   45,   46,   47,   48,   49,   50,   51,   52,   53,   54,
+        55,   56,   57,   58,   59,   60,   61,   62,   63,   64,   65,   66,
+        67,   68,   69,   70,   71,   72,   73,   74,   75,   76,   77,   78,
+        79,   80,   81,   82,   83,   84,   85,   86,   87,   88,   89,   90,
+        91,   92,   93,   94,   95,   96,   97,   98,   99,   100,  101,  102,
+        104,  106,  108,  110,  112,  114,  116,  118,  120,  122,  124,  126,
+        128,  130,  132,  134,  136,  138,  140,  142,  144,  146,  148,  150,
+        152,  155,  158,  161,  164,  167,  170,  173,  176,  179,  182,  185,
+        188,  191,  194,  197,  200,  203,  207,  211,  215,  219,  223,  227,
+        231,  235,  239,  243,  247,  251,  255,  260,  265,  270,  275,  280,
+        285,  290,  295,  300,  305,  311,  317,  323,  329,  335,  341,  347,
+        353,  359,  366,  373,  380,  387,  394,  401,  408,  416,  424,  432,
+        440,  448,  456,  465,  474,  483,  492,  501,  510,  520,  530,  540,
+        550,  560,  571,  582,  593,  604,  615,  627,  639,  651,  663,  676,
+        689,  702,  715,  729,  743,  757,  771,  786,  801,  816,  832,  848,
+        864,  881,  898,  915,  933,  951,  969,  988,  1007, 1026, 1046, 1066,
+        1087, 1108, 1129, 1151, 1173, 1196, 1219, 1243, 1267, 1292, 1317, 1343,
+        1369, 1396, 1423, 1451, 1479, 1508, 1537, 1567, 1597, 1628, 1660, 1692,
+        1725, 1759, 1793, 1828,
+    },
+    {
+        4,    9,    11,   13,   16,   18,   21,   24,   27,   30,   33,   37,
+        40,   44,   48,   51,   55,   59,   63,   67,   71,   75,   79,   83,
+        88,   92,   96,   100,  105,  109,  114,  118,  122,  127,  131,  136,
+        140,  145,  149,  154,  158,  163,  168,  172,  177,  181,  186,  190,
+        195,  199,  204,  208,  213,  217,  222,  226,  231,  235,  240,  244,
+        249,  253,  258,  262,  267,  271,  275,  280,  284,  289,  293,  297,
+        302,  306,  311,  315,  319,  324,  328,  332,  337,  341,  345,  349,
+        354,  358,  362,  367,  371,  375,  379,  384,  388,  392,  396,  401,
+        409,  417,  425,  433,  441,  449,  458,  466,  474,  482,  490,  498,
+        506,  514,  523,  531,  539,  547,  555,  563,  571,  579,  588,  596,
+        604,  616,  628,  640,  652,  664,  676,  688,  700,  713,  725,  737,
+        749,  761,  773,  785,  797,  809,  825,  841,  857,  873,  889,  905,
+        922,  938,  954,  970,  986,  1002, 1018, 1038, 1058, 1078, 1098, 1118,
+        1138, 1158, 1178, 1198, 1218, 1242, 1266, 1290, 1314, 1338, 1362, 1386,
+        1411, 1435, 1463, 1491, 1519, 1547, 1575, 1603, 1631, 1663, 1695, 1727,
+        1759, 1791, 1823, 1859, 1895, 1931, 1967, 2003, 2039, 2079, 2119, 2159,
+        2199, 2239, 2283, 2327, 2371, 2415, 2459, 2507, 2555, 2603, 2651, 2703,
+        2755, 2807, 2859, 2915, 2971, 3027, 3083, 3143, 3203, 3263, 3327, 3391,
+        3455, 3523, 3591, 3659, 3731, 3803, 3876, 3952, 4028, 4104, 4184, 4264,
+        4348, 4432, 4516, 4604, 4692, 4784, 4876, 4972, 5068, 5168, 5268, 5372,
+        5476, 5584, 5692, 5804, 5916, 6032, 6148, 6268, 6388, 6512, 6640, 6768,
+        6900, 7036, 7172, 7312
+   }
+};
+// clang-format on
+
+static_assert(arraysize(kDcQLookup[0]) == arraysize(kAcQLookup[0]),
+              "quantizer lookup arrays of incorrect size");
+
+size_t ClampQ(size_t q) {
+  return std::min(q, kQIndexRange - 1);
+}
+
+int ClampLf(int lf) {
+  const int kMaxLoopFilterLevel = 63;
+  return std::min(std::max(0, lf), kMaxLoopFilterLevel);
+}
+
+}  // namespace
+
 bool Vp9FrameHeader::IsKeyframe() const {
   // When show_existing_frame is true, the frame header does not precede an
   // actual frame to be decoded, so frame_type does not apply (and is not read
@@ -107,7 +235,7 @@
 Vp9Parser::Context::Vp9FrameContextManager::Vp9FrameContextManager()
     : weak_ptr_factory_(this) {}
 
-Vp9Parser::Context::Vp9FrameContextManager::~Vp9FrameContextManager() {}
+Vp9Parser::Context::Vp9FrameContextManager::~Vp9FrameContextManager() = default;
 
 const Vp9FrameContext&
 Vp9Parser::Context::Vp9FrameContextManager::frame_context() const {
@@ -205,7 +333,7 @@
   Reset();
 }
 
-Vp9Parser::~Vp9Parser() {}
+Vp9Parser::~Vp9Parser() = default;
 
 void Vp9Parser::SetStream(const uint8_t* stream, off_t stream_size) {
   DCHECK(stream);
@@ -223,14 +351,106 @@
   context_.Reset();
 }
 
+bool Vp9Parser::ParseUncompressedHeader(const FrameInfo& frame_info,
+                                        Vp9FrameHeader* fhdr,
+                                        Result* result) {
+  memset(&curr_frame_header_, 0, sizeof(curr_frame_header_));
+  *result = kInvalidStream;
+
+  Vp9UncompressedHeaderParser uncompressed_parser(&context_);
+  if (!uncompressed_parser.Parse(frame_info.ptr, frame_info.size,
+                                 &curr_frame_header_)) {
+    *result = kInvalidStream;
+    return true;
+  }
+
+  if (curr_frame_header_.header_size_in_bytes == 0) {
+    // Verify padding bits are zero.
+    for (off_t i = curr_frame_header_.uncompressed_header_size;
+         i < frame_info.size; i++) {
+      if (frame_info.ptr[i] != 0) {
+        DVLOG(1) << "Padding bits are not zeros.";
+        *result = kInvalidStream;
+        return true;
+      }
+    }
+    *fhdr = curr_frame_header_;
+    *result = kOk;
+    return true;
+  }
+  if (curr_frame_header_.uncompressed_header_size +
+          curr_frame_header_.header_size_in_bytes >
+      base::checked_cast<size_t>(frame_info.size)) {
+    DVLOG(1) << "header_size_in_bytes="
+             << curr_frame_header_.header_size_in_bytes
+             << " is larger than bytes left in buffer: "
+             << frame_info.size - curr_frame_header_.uncompressed_header_size;
+    *result = kInvalidStream;
+    return true;
+  }
+
+  return false;
+}
+
+bool Vp9Parser::ParseCompressedHeader(const FrameInfo& frame_info,
+                                      Result* result) {
+  *result = kInvalidStream;
+  size_t frame_context_idx = curr_frame_header_.frame_context_idx;
+  const Context::Vp9FrameContextManager& context_to_load =
+      context_.frame_context_managers_[frame_context_idx];
+  if (!context_to_load.initialized()) {
+    // 8.2 Frame order constraints
+    // must load an initialized set of probabilities.
+    DVLOG(1) << "loading uninitialized frame context, index="
+             << frame_context_idx;
+    *result = kInvalidStream;
+    return true;
+  }
+  if (context_to_load.needs_client_update()) {
+    DVLOG(3) << "waiting frame_context_idx=" << frame_context_idx
+             << " to update";
+    curr_frame_info_ = frame_info;
+    *result = kAwaitingRefresh;
+    return true;
+  }
+  curr_frame_header_.initial_frame_context = curr_frame_header_.frame_context =
+      context_to_load.frame_context();
+
+  Vp9CompressedHeaderParser compressed_parser;
+  if (!compressed_parser.Parse(
+          frame_info.ptr + curr_frame_header_.uncompressed_header_size,
+          curr_frame_header_.header_size_in_bytes, &curr_frame_header_)) {
+    *result = kInvalidStream;
+    return true;
+  }
+
+  if (curr_frame_header_.refresh_frame_context) {
+    // In frame parallel mode, we can refresh the context without decoding
+    // tile data.
+    if (curr_frame_header_.frame_parallel_decoding_mode) {
+      context_.UpdateFrameContext(frame_context_idx,
+                                  curr_frame_header_.frame_context);
+    } else {
+      context_.MarkFrameContextForUpdate(frame_context_idx);
+    }
+  }
+  return false;
+}
+
 Vp9Parser::Result Vp9Parser::ParseNextFrame(Vp9FrameHeader* fhdr) {
   DCHECK(fhdr);
   DVLOG(2) << "ParseNextFrame";
+  FrameInfo frame_info;
+  Result result;
 
   // If |curr_frame_info_| is valid, uncompressed header was parsed into
   // |curr_frame_header_| and we are awaiting context update to proceed with
   // compressed header parsing.
-  if (!curr_frame_info_.IsValid()) {
+  if (curr_frame_info_.IsValid()) {
+    DCHECK(parsing_compressed_header_);
+    frame_info = curr_frame_info_;
+    curr_frame_info_.Reset();
+  } else {
     if (frames_.empty()) {
       // No frames to be decoded, if there is no more stream, request more.
       if (!stream_)
@@ -244,85 +464,26 @@
       }
     }
 
-    curr_frame_info_ = frames_.front();
+    frame_info = frames_.front();
     frames_.pop_front();
 
-    memset(&curr_frame_header_, 0, sizeof(curr_frame_header_));
-
-    Vp9UncompressedHeaderParser uncompressed_parser(&context_);
-    if (!uncompressed_parser.Parse(curr_frame_info_.ptr, curr_frame_info_.size,
-                                   &curr_frame_header_))
-      return kInvalidStream;
-
-    if (curr_frame_header_.header_size_in_bytes == 0) {
-      // Verify padding bits are zero.
-      for (off_t i = curr_frame_header_.uncompressed_header_size;
-           i < curr_frame_info_.size; i++) {
-        if (curr_frame_info_.ptr[i] != 0) {
-          DVLOG(1) << "Padding bits are not zeros.";
-          return kInvalidStream;
-        }
-      }
-      *fhdr = curr_frame_header_;
-      curr_frame_info_.Reset();
-      return kOk;
-    }
-    if (curr_frame_header_.uncompressed_header_size +
-            curr_frame_header_.header_size_in_bytes >
-        base::checked_cast<size_t>(curr_frame_info_.size)) {
-      DVLOG(1) << "header_size_in_bytes="
-               << curr_frame_header_.header_size_in_bytes
-               << " is larger than bytes left in buffer: "
-               << curr_frame_info_.size -
-                      curr_frame_header_.uncompressed_header_size;
-      return kInvalidStream;
-    }
+    if (ParseUncompressedHeader(frame_info, fhdr, &result))
+      return result;
   }
 
   if (parsing_compressed_header_) {
-    size_t frame_context_idx = curr_frame_header_.frame_context_idx;
-    const Context::Vp9FrameContextManager& context_to_load =
-        context_.frame_context_managers_[frame_context_idx];
-    if (!context_to_load.initialized()) {
-      // 8.2 Frame order constraints
-      // must load an initialized set of probabilities.
-      DVLOG(1) << "loading uninitialized frame context, index="
-               << frame_context_idx;
-      return kInvalidStream;
-    }
-    if (context_to_load.needs_client_update()) {
-      DVLOG(3) << "waiting frame_context_idx=" << frame_context_idx
-               << " to update";
-      return kAwaitingRefresh;
-    }
-    curr_frame_header_.initial_frame_context =
-        curr_frame_header_.frame_context = context_to_load.frame_context();
-
-    Vp9CompressedHeaderParser compressed_parser;
-    if (!compressed_parser.Parse(
-            curr_frame_info_.ptr + curr_frame_header_.uncompressed_header_size,
-            curr_frame_header_.header_size_in_bytes, &curr_frame_header_)) {
-      return kInvalidStream;
-    }
-
-    if (curr_frame_header_.refresh_frame_context) {
-      // In frame parallel mode, we can refresh the context without decoding
-      // tile data.
-      if (curr_frame_header_.frame_parallel_decoding_mode) {
-        context_.UpdateFrameContext(frame_context_idx,
-                                    curr_frame_header_.frame_context);
-      } else {
-        context_.MarkFrameContextForUpdate(frame_context_idx);
-      }
+    if (ParseCompressedHeader(frame_info, &result)) {
+      DCHECK(result != kAwaitingRefresh || curr_frame_info_.IsValid());
+      return result;
     }
   }
 
-  SetupSegmentationDequant();
+  if (!SetupSegmentationDequant())
+    return kInvalidStream;
   SetupLoopFilter();
   UpdateSlots();
 
   *fhdr = curr_frame_header_;
-  curr_frame_info_.Reset();
   return kOk;
 }
 
@@ -398,86 +559,6 @@
   return frames;
 }
 
-// 8.6.1
-const size_t QINDEX_RANGE = 256;
-const int16_t kDcQLookup[QINDEX_RANGE] = {
-  4,       8,    8,    9,   10,   11,   12,   12,
-  13,     14,   15,   16,   17,   18,   19,   19,
-  20,     21,   22,   23,   24,   25,   26,   26,
-  27,     28,   29,   30,   31,   32,   32,   33,
-  34,     35,   36,   37,   38,   38,   39,   40,
-  41,     42,   43,   43,   44,   45,   46,   47,
-  48,     48,   49,   50,   51,   52,   53,   53,
-  54,     55,   56,   57,   57,   58,   59,   60,
-  61,     62,   62,   63,   64,   65,   66,   66,
-  67,     68,   69,   70,   70,   71,   72,   73,
-  74,     74,   75,   76,   77,   78,   78,   79,
-  80,     81,   81,   82,   83,   84,   85,   85,
-  87,     88,   90,   92,   93,   95,   96,   98,
-  99,    101,  102,  104,  105,  107,  108,  110,
-  111,   113,  114,  116,  117,  118,  120,  121,
-  123,   125,  127,  129,  131,  134,  136,  138,
-  140,   142,  144,  146,  148,  150,  152,  154,
-  156,   158,  161,  164,  166,  169,  172,  174,
-  177,   180,  182,  185,  187,  190,  192,  195,
-  199,   202,  205,  208,  211,  214,  217,  220,
-  223,   226,  230,  233,  237,  240,  243,  247,
-  250,   253,  257,  261,  265,  269,  272,  276,
-  280,   284,  288,  292,  296,  300,  304,  309,
-  313,   317,  322,  326,  330,  335,  340,  344,
-  349,   354,  359,  364,  369,  374,  379,  384,
-  389,   395,  400,  406,  411,  417,  423,  429,
-  435,   441,  447,  454,  461,  467,  475,  482,
-  489,   497,  505,  513,  522,  530,  539,  549,
-  559,   569,  579,  590,  602,  614,  626,  640,
-  654,   668,  684,  700,  717,  736,  755,  775,
-  796,   819,  843,  869,  896,  925,  955,  988,
-  1022, 1058, 1098, 1139, 1184, 1232, 1282, 1336,
-};
-
-const int16_t kAcQLookup[QINDEX_RANGE] = {
-  4,       8,    9,   10,   11,   12,   13,   14,
-  15,     16,   17,   18,   19,   20,   21,   22,
-  23,     24,   25,   26,   27,   28,   29,   30,
-  31,     32,   33,   34,   35,   36,   37,   38,
-  39,     40,   41,   42,   43,   44,   45,   46,
-  47,     48,   49,   50,   51,   52,   53,   54,
-  55,     56,   57,   58,   59,   60,   61,   62,
-  63,     64,   65,   66,   67,   68,   69,   70,
-  71,     72,   73,   74,   75,   76,   77,   78,
-  79,     80,   81,   82,   83,   84,   85,   86,
-  87,     88,   89,   90,   91,   92,   93,   94,
-  95,     96,   97,   98,   99,  100,  101,  102,
-  104,   106,  108,  110,  112,  114,  116,  118,
-  120,   122,  124,  126,  128,  130,  132,  134,
-  136,   138,  140,  142,  144,  146,  148,  150,
-  152,   155,  158,  161,  164,  167,  170,  173,
-  176,   179,  182,  185,  188,  191,  194,  197,
-  200,   203,  207,  211,  215,  219,  223,  227,
-  231,   235,  239,  243,  247,  251,  255,  260,
-  265,   270,  275,  280,  285,  290,  295,  300,
-  305,   311,  317,  323,  329,  335,  341,  347,
-  353,   359,  366,  373,  380,  387,  394,  401,
-  408,   416,  424,  432,  440,  448,  456,  465,
-  474,   483,  492,  501,  510,  520,  530,  540,
-  550,   560,  571,  582,  593,  604,  615,  627,
-  639,   651,  663,  676,  689,  702,  715,  729,
-  743,   757,  771,  786,  801,  816,  832,  848,
-  864,   881,  898,  915,  933,  951,  969,  988,
-  1007, 1026, 1046, 1066, 1087, 1108, 1129, 1151,
-  1173, 1196, 1219, 1243, 1267, 1292, 1317, 1343,
-  1369, 1396, 1423, 1451, 1479, 1508, 1537, 1567,
-  1597, 1628, 1660, 1692, 1725, 1759, 1793, 1828,
-};
-
-static_assert(arraysize(kDcQLookup) == arraysize(kAcQLookup),
-              "quantizer lookup arrays of incorrect size");
-
-static size_t ClampQ(size_t q) {
-  return std::min(std::max(static_cast<size_t>(0), q),
-                  arraysize(kDcQLookup) - 1);
-}
-
 // 8.6.1 Dequantization functions
 size_t Vp9Parser::GetQIndex(const Vp9QuantizationParams& quant,
                             size_t segid) const {
@@ -497,40 +578,40 @@
 }
 
 // 8.6.1 Dequantization functions
-void Vp9Parser::SetupSegmentationDequant() {
+bool Vp9Parser::SetupSegmentationDequant() {
   const Vp9QuantizationParams& quant = curr_frame_header_.quant_params;
   Vp9SegmentationParams& segmentation = context_.segmentation_;
 
-  DLOG_IF(ERROR, curr_frame_header_.bit_depth > 8)
-      << "bit_depth > 8 is not supported "
-         "yet, kDcQLookup and kAcQLookup "
-         "need extended";
+  if (curr_frame_header_.bit_depth > 10) {
+    DLOG(ERROR) << "bit_depth > 10 is not supported yet, kDcQLookup and "
+                   "kAcQLookup need to be extended";
+    return false;
+  }
+  const size_t bit_depth_index = (curr_frame_header_.bit_depth == 8) ? 0 : 1;
+
   if (segmentation.enabled) {
     for (size_t i = 0; i < Vp9SegmentationParams::kNumSegments; ++i) {
       const size_t q_index = GetQIndex(quant, i);
       segmentation.y_dequant[i][0] =
-          kDcQLookup[ClampQ(q_index + quant.delta_q_y_dc)];
-      segmentation.y_dequant[i][1] = kAcQLookup[ClampQ(q_index)];
+          kDcQLookup[bit_depth_index][ClampQ(q_index + quant.delta_q_y_dc)];
+      segmentation.y_dequant[i][1] =
+          kAcQLookup[bit_depth_index][ClampQ(q_index)];
       segmentation.uv_dequant[i][0] =
-          kDcQLookup[ClampQ(q_index + quant.delta_q_uv_dc)];
+          kDcQLookup[bit_depth_index][ClampQ(q_index + quant.delta_q_uv_dc)];
       segmentation.uv_dequant[i][1] =
-          kAcQLookup[ClampQ(q_index + quant.delta_q_uv_ac)];
+          kAcQLookup[bit_depth_index][ClampQ(q_index + quant.delta_q_uv_ac)];
     }
   } else {
     const size_t q_index = quant.base_q_idx;
     segmentation.y_dequant[0][0] =
-        kDcQLookup[ClampQ(q_index + quant.delta_q_y_dc)];
-    segmentation.y_dequant[0][1] = kAcQLookup[ClampQ(q_index)];
+        kDcQLookup[bit_depth_index][ClampQ(q_index + quant.delta_q_y_dc)];
+    segmentation.y_dequant[0][1] = kAcQLookup[bit_depth_index][ClampQ(q_index)];
     segmentation.uv_dequant[0][0] =
-        kDcQLookup[ClampQ(q_index + quant.delta_q_uv_dc)];
+        kDcQLookup[bit_depth_index][ClampQ(q_index + quant.delta_q_uv_dc)];
     segmentation.uv_dequant[0][1] =
-        kAcQLookup[ClampQ(q_index + quant.delta_q_uv_ac)];
+        kAcQLookup[bit_depth_index][ClampQ(q_index + quant.delta_q_uv_ac)];
   }
-}
-
-static int ClampLf(int lf) {
-  const int kMaxLoopFilterLevel = 63;
-  return std::min(std::max(0, lf), kMaxLoopFilterLevel);
+  return true;
 }
 
 // 8.8.1 Loop filter frame init process
diff --git a/vda/vp9_parser.h b/vda/vp9_parser.h
index c6e1d9f..ab1fa57 100644
--- a/vda/vp9_parser.h
+++ b/vda/vp9_parser.h
@@ -9,6 +9,7 @@
 //
 // See media::VP9Decoder for example usage.
 //
+// Note: ported from Chromium commit head: ec6c6e0
 #ifndef VP9_PARSER_H_
 #define VP9_PARSER_H_
 
@@ -404,8 +405,22 @@
 
   std::deque<FrameInfo> ParseSuperframe();
 
+  // Returns true and populates |result| with the parsing result if parsing of
+  // current frame is finished (possibly unsuccessfully). |fhdr| will only be
+  // populated and valid if |result| is kOk. Otherwise return false, indicating
+  // that the compressed header must be parsed next.
+  bool ParseUncompressedHeader(const FrameInfo& frame_info,
+                               Vp9FrameHeader* fhdr,
+                               Result* result);
+
+  // Returns true if parsing of current frame is finished and |result| will be
+  // populated with value of parsing result. Otherwise, needs to continue setup
+  // current frame.
+  bool ParseCompressedHeader(const FrameInfo& frame_info, Result* result);
+
   size_t GetQIndex(const Vp9QuantizationParams& quant, size_t segid) const;
-  void SetupSegmentationDequant();
+  // Returns true if the setup succeeded.
+  bool SetupSegmentationDequant();
   void SetupLoopFilter();
   void UpdateSlots();
 
@@ -415,7 +430,7 @@
   // Remaining bytes in stream_.
   off_t bytes_left_;
 
-  bool parsing_compressed_header_;
+  const bool parsing_compressed_header_;
 
   // FrameInfo for the remaining frames in the current superframe to be parsed.
   std::deque<FrameInfo> frames_;
diff --git a/vda/vp9_picture.cc b/vda/vp9_picture.cc
index a99427f..df2c3b0 100644
--- a/vda/vp9_picture.cc
+++ b/vda/vp9_picture.cc
@@ -1,6 +1,7 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 6e70beb
 
 #include "vp9_picture.h"
 
diff --git a/vda/vp9_picture.h b/vda/vp9_picture.h
index 23e299b..efff37b 100644
--- a/vda/vp9_picture.h
+++ b/vda/vp9_picture.h
@@ -1,6 +1,7 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 70340ce
 
 #ifndef VP9_PICTURE_H_
 #define VP9_PICTURE_H_
@@ -9,13 +10,14 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "rect.h"
 #include "vp9_parser.h"
 
 namespace media {
 
 class V4L2VP9Picture;
 
-class VP9Picture : public base::RefCounted<VP9Picture> {
+class VP9Picture : public base::RefCountedThreadSafe<VP9Picture> {
  public:
   VP9Picture();
 
@@ -23,8 +25,13 @@
 
   std::unique_ptr<Vp9FrameHeader> frame_hdr;
 
+  // The visible size of picture. This could be either parsed from frame
+  // header, or set to Rect(0, 0) for indicating invalid values or
+  // not available.
+  Rect visible_rect;
+
  protected:
-  friend class base::RefCounted<VP9Picture>;
+  friend class base::RefCountedThreadSafe<VP9Picture>;
   virtual ~VP9Picture();
 
   DISALLOW_COPY_AND_ASSIGN(VP9Picture);
diff --git a/vda/vp9_raw_bits_reader.cc b/vda/vp9_raw_bits_reader.cc
index 7cad4d9..dea06e0 100644
--- a/vda/vp9_raw_bits_reader.cc
+++ b/vda/vp9_raw_bits_reader.cc
@@ -1,6 +1,7 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: 2de6929
 
 #include "vp9_raw_bits_reader.h"
 
@@ -13,7 +14,7 @@
 
 Vp9RawBitsReader::Vp9RawBitsReader() : valid_(true) {}
 
-Vp9RawBitsReader::~Vp9RawBitsReader() {}
+Vp9RawBitsReader::~Vp9RawBitsReader() = default;
 
 void Vp9RawBitsReader::Initialize(const uint8_t* data, size_t size) {
   DCHECK(data);
diff --git a/vda/vp9_raw_bits_reader.h b/vda/vp9_raw_bits_reader.h
index 9f112b8..04ad413 100644
--- a/vda/vp9_raw_bits_reader.h
+++ b/vda/vp9_raw_bits_reader.h
@@ -1,6 +1,7 @@
 // Copyright 2015 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.
+// Note: ported from Chromium commit head: e5a9a62
 
 #ifndef VP9_RAW_BITS_READER_H_
 #define VP9_RAW_BITS_READER_H_
diff --git a/vda/vp9_uncompressed_header_parser.cc b/vda/vp9_uncompressed_header_parser.cc
index 067b40c..f6dc2eb 100644
--- a/vda/vp9_uncompressed_header_parser.cc
+++ b/vda/vp9_uncompressed_header_parser.cc
@@ -1,6 +1,7 @@
 // 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.
+// Note: ported from Chromium commit head: f06caa0
 
 #include "vp9_uncompressed_header_parser.h"
 
@@ -789,7 +790,7 @@
       for (size_t i = 0; i < Vp9LoopFilterParams::kNumModeDeltas; i++) {
         loop_filter.update_mode_deltas[i] = reader_.ReadBool();
         if (loop_filter.update_mode_deltas[i])
-          loop_filter.mode_deltas[i] = reader_.ReadLiteral(6);
+          loop_filter.mode_deltas[i] = reader_.ReadSignedLiteral(6);
       }
     }
   }
diff --git a/vda/vp9_uncompressed_header_parser.h b/vda/vp9_uncompressed_header_parser.h
index 655ba38..6780d38 100644
--- a/vda/vp9_uncompressed_header_parser.h
+++ b/vda/vp9_uncompressed_header_parser.h
@@ -1,6 +1,7 @@
 // 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.
+// Note: ported from Chromium commit head: e5a9a62
 
 #ifndef VP9_UNCOMPRESSED_HEADER_PARSER_H_
 #define VP9_UNCOMPRESSED_HEADER_PARSER_H_
diff --git a/vndk/C2VDAStore.cpp b/vndk/C2VDAStore.cpp
index 8c57e88..42ce6df 100644
--- a/vndk/C2VDAStore.cpp
+++ b/vndk/C2VDAStore.cpp
@@ -94,7 +94,9 @@
 #ifdef ANDROID_VERSION_NYC
         allocator = std::make_shared<C2AllocatorCrosGralloc>();
 #else
-        allocator = std::make_shared<C2AllocatorGralloc>();
+        // TODO is this supposed to be the platform's gralloc allocator?
+        // perhaps extend C2PlatformAllocatorStore
+        allocator = std::make_shared<C2AllocatorGralloc>(C2AllocatorStore::VENDOR_START);
 #endif
         mCrosGrallocAllocator = allocator;
     }