summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorjohnme@chromium.org <johnme@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-22 14:44:22 +0000
committerjohnme@chromium.org <johnme@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-22 14:44:22 +0000
commitfe2e8506eb31302bd9ea251cba81b37cf6f9c2f6 (patch)
treeaaab9b51f30ef464cdf9492b5ec69f5fcbbbd12f /media
parent49d75aea3cb6fbc29afa2b0b567ef5325b694ff5 (diff)
downloadchromium_src-fe2e8506eb31302bd9ea251cba81b37cf6f9c2f6.zip
chromium_src-fe2e8506eb31302bd9ea251cba81b37cf6f9c2f6.tar.gz
chromium_src-fe2e8506eb31302bd9ea251cba81b37cf6f9c2f6.tar.bz2
Revert of Clean up. Experimental user avatars removed. (https://codereview.chromium.org/395133002/)
Reason for revert: This broke build: http://build.chromium.org/p/chromium.webkit/builders/Linux%20ChromiumOS%20Tests%20%28dbg%29%282%29/builds/419 With error: /mnt/data/b/build/slave/Linux_ChromiumOS_Tests__dbg__2_/build/src/out/Debug/app_shell_browsertests: symbol lookup error: /mnt/data/b/build/slave/Linux_ChromiumOS_Tests__dbg__2_/build/src/out/Debug/lib/libmedia.so: undefined symbol: Ebml_Serialize Original issue's description: > Clean up. Experimental user avatars removed. > > BUG=387738 > > Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=284666 TBR=scherkus@chromium.org,nkostylev@chromium.org,merkulova@chromium.org NOTREECHECKS=true NOTRY=true BUG=387738 Review URL: https://codereview.chromium.org/411523005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284676 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/BUILD.gn21
-rw-r--r--media/formats/webm/chromeos/DEPS4
-rw-r--r--media/formats/webm/chromeos/ebml_writer.cc33
-rw-r--r--media/formats/webm/chromeos/ebml_writer.h21
-rw-r--r--media/formats/webm/chromeos/webm_encoder.cc321
-rw-r--r--media/formats/webm/chromeos/webm_encoder.h106
-rw-r--r--media/media.gyp13
7 files changed, 519 insertions, 0 deletions
diff --git a/media/BUILD.gn b/media/BUILD.gn
index e2209aa..6b710be 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -450,6 +450,27 @@ component("media") {
}
}
+ if (is_chromeos) {
+ # A simple WebM encoder for animated avatars on ChromeOS.
+ sources += [
+ "formats/webm/chromeos/ebml_writer.cc",
+ "formats/webm/chromeos/ebml_writer.h",
+ "formats/webm/chromeos/webm_encoder.cc",
+ "formats/webm/chromeos/webm_encoder.h",
+ ]
+ deps += [
+ "//third_party/libvpx",
+ "//third_party/libyuv"
+ ]
+ # For VaapiVideoEncodeAccelerator.
+ if (cpu_arch != "arm" && use_x11) {
+ sources += [
+ "filters/h264_bitstream_buffer.cc",
+ "filters/h264_bitstream_buffer.h",
+ ]
+ }
+ }
+
if (!is_ios) {
deps += [ "//third_party/libyuv" ]
}
diff --git a/media/formats/webm/chromeos/DEPS b/media/formats/webm/chromeos/DEPS
new file mode 100644
index 0000000..a4378dc
--- /dev/null
+++ b/media/formats/webm/chromeos/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+libyuv",
+ "+third_party/libvpx",
+]
diff --git a/media/formats/webm/chromeos/ebml_writer.cc b/media/formats/webm/chromeos/ebml_writer.cc
new file mode 100644
index 0000000..c00063f
--- /dev/null
+++ b/media/formats/webm/chromeos/ebml_writer.cc
@@ -0,0 +1,33 @@
+// 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.
+
+#include "media/formats/webm/chromeos/ebml_writer.h"
+
+#include "media/base/media_export.h"
+
+extern "C" {
+#include "third_party/libvpx/source/libvpx/third_party/libmkv/EbmlWriter.h"
+
+EbmlGlobal::EbmlGlobal() {
+}
+
+EbmlGlobal::~EbmlGlobal() {
+}
+
+// These functions must be in the global namespace and visible to libmkv.
+
+void MEDIA_EXPORT Ebml_Write(EbmlGlobal* glob,
+ const void* buffer,
+ unsigned long len) {
+ glob->write_cb.Run(buffer, len);
+}
+
+void MEDIA_EXPORT Ebml_Serialize(EbmlGlobal* glob,
+ const void* buffer,
+ int buffer_size,
+ unsigned long len) {
+ glob->serialize_cb.Run(buffer, buffer_size, len);
+}
+
+} // extern "C"
diff --git a/media/formats/webm/chromeos/ebml_writer.h b/media/formats/webm/chromeos/ebml_writer.h
new file mode 100644
index 0000000..3c1faa0
--- /dev/null
+++ b/media/formats/webm/chromeos/ebml_writer.h
@@ -0,0 +1,21 @@
+// 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.
+
+#ifndef MEDIA_FORMATS_WEBM_CHROMEOS_EBML_WRITER_H_
+#define MEDIA_FORMATS_WEBM_CHROMEOS_EBML_WRITER_H_
+
+#include "base/callback.h"
+
+// This struct serves as a bridge betweeen static libmkv interface and Chrome's
+// base::Callback. Must be in the global namespace. See EbmlWriter.h.
+struct EbmlGlobal {
+ EbmlGlobal();
+ ~EbmlGlobal();
+
+ base::Callback<void(const void* buffer, unsigned long len)> write_cb;
+ base::Callback<void(const void* buffer, int buffer_size, unsigned long len)>
+ serialize_cb;
+};
+
+#endif // MEDIA_FORMATS_WEBM_CHROMEOS_EBML_WRITER_H_
diff --git a/media/formats/webm/chromeos/webm_encoder.cc b/media/formats/webm/chromeos/webm_encoder.cc
new file mode 100644
index 0000000..4b5c782
--- /dev/null
+++ b/media/formats/webm/chromeos/webm_encoder.cc
@@ -0,0 +1,321 @@
+// 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.
+
+#include "media/formats/webm/chromeos/webm_encoder.h"
+
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "libyuv/convert.h"
+#include "libyuv/video_common.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+extern "C" {
+// Getting the right degree of C compatibility has been a constant struggle.
+// - Stroustrup, C++ Report, 12(7), July/August 2000.
+#define private priv
+#include "third_party/libvpx/source/libvpx/third_party/libmkv/EbmlIDs.h"
+#include "third_party/libvpx/source/libvpx/third_party/libmkv/EbmlWriter.h"
+#undef private
+}
+
+// Number of encoder threads to use.
+static const int kNumEncoderThreads = 2;
+
+// Need a fixed size serializer for the track ID. libmkv provides a 64 bit
+// one, but not a 32 bit one.
+static void Ebml_SerializeUnsigned32(EbmlGlobal* ebml,
+ unsigned long class_id,
+ uint64_t value) {
+ uint8 size_serialized = 4 | 0x80;
+ Ebml_WriteID(ebml, class_id);
+ Ebml_Serialize(ebml, &size_serialized, sizeof(size_serialized), 1);
+ Ebml_Serialize(ebml, &value, sizeof(value), 4);
+}
+
+// Wrapper functor for vpx_codec_destroy().
+struct VpxCodecDeleter {
+ void operator()(vpx_codec_ctx_t* codec) {
+ vpx_codec_destroy(codec);
+ }
+};
+
+// Wrapper functor for vpx_img_free().
+struct VpxImgDeleter {
+ void operator()(vpx_image_t* image) {
+ vpx_img_free(image);
+ }
+};
+
+namespace media {
+
+namespace chromeos {
+
+WebmEncoder::WebmEncoder(const base::FilePath& output_path,
+ int bitrate,
+ bool realtime)
+ : bitrate_(bitrate),
+ deadline_(realtime ? VPX_DL_REALTIME : VPX_DL_GOOD_QUALITY),
+ output_path_(output_path),
+ has_errors_(false) {
+ ebml_writer_.write_cb = base::Bind(
+ &WebmEncoder::EbmlWrite, base::Unretained(this));
+ ebml_writer_.serialize_cb = base::Bind(
+ &WebmEncoder::EbmlSerialize, base::Unretained(this));
+}
+
+WebmEncoder::~WebmEncoder() {
+}
+
+bool WebmEncoder::EncodeFromSprite(const SkBitmap& sprite,
+ int fps_n,
+ int fps_d) {
+ DCHECK(!sprite.isNull());
+ DCHECK(!sprite.empty());
+
+ has_errors_ = false;
+ width_ = sprite.width();
+ height_ = sprite.width();
+ fps_.num = fps_n;
+ fps_.den = fps_d;
+
+ // Sprite is tiled vertically.
+ frame_count_ = sprite.height() / width_;
+
+ vpx_image_t image;
+ vpx_img_alloc(&image, VPX_IMG_FMT_I420, width_, height_, 16);
+ // Ensure that image is freed after return.
+ scoped_ptr<vpx_image_t, VpxImgDeleter> image_ptr(&image);
+
+ const vpx_codec_iface_t* codec_iface = vpx_codec_vp8_cx();
+ DCHECK(codec_iface);
+ vpx_codec_err_t ret = vpx_codec_enc_config_default(codec_iface, &config_, 0);
+ DCHECK_EQ(VPX_CODEC_OK, ret);
+
+ config_.rc_target_bitrate = bitrate_;
+ config_.g_w = width_;
+ config_.g_h = height_;
+ config_.g_pass = VPX_RC_ONE_PASS;
+ config_.g_profile = 0; // Default profile.
+ config_.g_threads = kNumEncoderThreads;
+ config_.rc_min_quantizer = 0;
+ config_.rc_max_quantizer = 63; // Maximum possible range.
+ config_.g_timebase.num = fps_.den;
+ config_.g_timebase.den = fps_.num;
+ config_.kf_mode = VPX_KF_AUTO; // Auto key frames.
+
+ vpx_codec_ctx_t codec;
+ ret = vpx_codec_enc_init(&codec, codec_iface, &config_, 0);
+ if (ret != VPX_CODEC_OK)
+ return false;
+ // Ensure that codec context is freed after return.
+ scoped_ptr<vpx_codec_ctx_t, VpxCodecDeleter> codec_ptr(&codec);
+
+ SkAutoLockPixels lock_sprite(sprite);
+
+ const uint8* src = reinterpret_cast<const uint8*>(sprite.getAddr32(0, 0));
+ size_t src_frame_size = sprite.getSize();
+ int crop_y = 0;
+
+ if (!WriteWebmHeader())
+ return false;
+
+ for (size_t frame = 0; frame < frame_count_ && !has_errors_; ++frame) {
+ int res = libyuv::ConvertToI420(
+ src, src_frame_size,
+ image.planes[VPX_PLANE_Y], image.stride[VPX_PLANE_Y],
+ image.planes[VPX_PLANE_U], image.stride[VPX_PLANE_U],
+ image.planes[VPX_PLANE_V], image.stride[VPX_PLANE_V],
+ 0, crop_y, // src origin
+ width_, sprite.height(), // src size
+ width_, height_, // dest size
+ libyuv::kRotate0,
+ libyuv::FOURCC_ARGB);
+ if (res) {
+ has_errors_ = true;
+ break;
+ }
+ crop_y += height_;
+
+ ret = vpx_codec_encode(&codec, &image, frame, 1, 0, deadline_);
+ if (ret != VPX_CODEC_OK) {
+ has_errors_ = true;
+ break;
+ }
+
+ vpx_codec_iter_t iter = NULL;
+ const vpx_codec_cx_pkt_t* packet;
+ while (!has_errors_ && (packet = vpx_codec_get_cx_data(&codec, &iter))) {
+ if (packet->kind == VPX_CODEC_CX_FRAME_PKT)
+ WriteWebmBlock(packet);
+ }
+ }
+
+ return WriteWebmFooter();
+}
+
+bool WebmEncoder::WriteWebmHeader() {
+ output_ = base::OpenFile(output_path_, "wb");
+ if (!output_)
+ return false;
+
+ // Global header.
+ StartSubElement(EBML);
+ {
+ Ebml_SerializeUnsigned(&ebml_writer_, EBMLVersion, 1);
+ Ebml_SerializeUnsigned(&ebml_writer_, EBMLReadVersion, 1);
+ Ebml_SerializeUnsigned(&ebml_writer_, EBMLMaxIDLength, 4);
+ Ebml_SerializeUnsigned(&ebml_writer_, EBMLMaxSizeLength, 8);
+ Ebml_SerializeString(&ebml_writer_, DocType, "webm");
+ Ebml_SerializeUnsigned(&ebml_writer_, DocTypeVersion, 2);
+ Ebml_SerializeUnsigned(&ebml_writer_, DocTypeReadVersion, 2);
+ }
+ EndSubElement(); // EBML
+
+ // Single segment with a video track.
+ StartSubElement(Segment);
+ {
+ StartSubElement(Info);
+ {
+ // All timecodes in the segment will be expressed in milliseconds.
+ Ebml_SerializeUnsigned(&ebml_writer_, TimecodeScale, 1000000);
+ double duration = 1000. * frame_count_ * fps_.den / fps_.num;
+ Ebml_SerializeFloat(&ebml_writer_, Segment_Duration, duration);
+ }
+ EndSubElement(); // Info
+
+ StartSubElement(Tracks);
+ {
+ StartSubElement(TrackEntry);
+ {
+ Ebml_SerializeUnsigned(&ebml_writer_, TrackNumber, 1);
+ Ebml_SerializeUnsigned32(&ebml_writer_, TrackUID, 1);
+ Ebml_SerializeUnsigned(&ebml_writer_, TrackType, 1); // Video
+ Ebml_SerializeString(&ebml_writer_, CodecID, "V_VP8");
+
+ StartSubElement(Video);
+ {
+ Ebml_SerializeUnsigned(&ebml_writer_, PixelWidth, width_);
+ Ebml_SerializeUnsigned(&ebml_writer_, PixelHeight, height_);
+ Ebml_SerializeUnsigned(&ebml_writer_, StereoMode, 0); // Mono
+ float fps = static_cast<float>(fps_.num) / fps_.den;
+ Ebml_SerializeFloat(&ebml_writer_, FrameRate, fps);
+ }
+ EndSubElement(); // Video
+ }
+ EndSubElement(); // TrackEntry
+ }
+ EndSubElement(); // Tracks
+
+ StartSubElement(Cluster); {
+ Ebml_SerializeUnsigned(&ebml_writer_, Timecode, 0);
+ } // Cluster left open.
+ } // Segment left open.
+
+ // No check for |has_errors_| here because |false| is only returned when
+ // opening file fails.
+ return true;
+}
+
+void WebmEncoder::WriteWebmBlock(const vpx_codec_cx_pkt_t* packet) {
+ bool is_keyframe = packet->data.frame.flags & VPX_FRAME_IS_KEY;
+ int64_t pts_ms = 1000 * packet->data.frame.pts * fps_.den / fps_.num;
+
+ DVLOG(1) << "Video packet @" << pts_ms << " ms "
+ << packet->data.frame.sz << " bytes "
+ << (is_keyframe ? "K" : "");
+
+ Ebml_WriteID(&ebml_writer_, SimpleBlock);
+
+ uint32 block_length = (packet->data.frame.sz + 4) | 0x10000000;
+ EbmlSerializeHelper(&block_length, 4);
+
+ uint8 track_number = 1 | 0x80;
+ EbmlSerializeHelper(&track_number, 1);
+
+ EbmlSerializeHelper(&pts_ms, 2);
+
+ uint8 flags = 0;
+ if (is_keyframe)
+ flags |= 0x80;
+ if (packet->data.frame.flags & VPX_FRAME_IS_INVISIBLE)
+ flags |= 0x08;
+ EbmlSerializeHelper(&flags, 1);
+
+ EbmlWrite(packet->data.frame.buf, packet->data.frame.sz);
+}
+
+bool WebmEncoder::WriteWebmFooter() {
+ EndSubElement(); // Cluster
+ EndSubElement(); // Segment
+ DCHECK(ebml_sub_elements_.empty());
+ return base::CloseFile(output_) && !has_errors_;
+}
+
+void WebmEncoder::StartSubElement(unsigned long class_id) {
+ Ebml_WriteID(&ebml_writer_, class_id);
+ ebml_sub_elements_.push(ftell(output_));
+ static const uint64_t kUnknownLen = 0x01FFFFFFFFFFFFFFLLU;
+ EbmlSerializeHelper(&kUnknownLen, 8);
+}
+
+void WebmEncoder::EndSubElement() {
+ DCHECK(!ebml_sub_elements_.empty());
+
+ long int end_pos = ftell(output_);
+ long int start_pos = ebml_sub_elements_.top();
+ ebml_sub_elements_.pop();
+
+ uint64_t size = (end_pos - start_pos - 8) | 0x0100000000000000ULL;
+ // Seek to the beginning of the sub-element and patch in the calculated size.
+ if (fseek(output_, start_pos, SEEK_SET)) {
+ has_errors_ = true;
+ LOG(ERROR) << "Error writing to " << output_path_.value();
+ }
+ EbmlSerializeHelper(&size, 8);
+
+ // Restore write position.
+ if (fseek(output_, end_pos, SEEK_SET)) {
+ has_errors_ = true;
+ LOG(ERROR) << "Error writing to " << output_path_.value();
+ }
+}
+
+void WebmEncoder::EbmlWrite(const void* buffer,
+ unsigned long len) {
+ if (fwrite(buffer, 1, len, output_) != len) {
+ has_errors_ = true;
+ LOG(ERROR) << "Error writing to " << output_path_.value();
+ }
+}
+
+template <class T>
+void WebmEncoder::EbmlSerializeHelper(const T* buffer, unsigned long len) {
+ for (int i = len - 1; i >= 0; i--) {
+ uint8 c = *buffer >> (i * CHAR_BIT);
+ EbmlWrite(&c, 1);
+ }
+}
+
+void WebmEncoder::EbmlSerialize(const void* buffer,
+ int buffer_size,
+ unsigned long len) {
+ switch (buffer_size) {
+ case 1:
+ return EbmlSerializeHelper(static_cast<const int8_t*>(buffer), len);
+ case 2:
+ return EbmlSerializeHelper(static_cast<const int16_t*>(buffer), len);
+ case 4:
+ return EbmlSerializeHelper(static_cast<const int32_t*>(buffer), len);
+ case 8:
+ return EbmlSerializeHelper(static_cast<const int64_t*>(buffer), len);
+ default:
+ NOTREACHED() << "Invalid EbmlSerialize length: " << len;
+ }
+}
+
+} // namespace chromeos
+
+} // namespace media
diff --git a/media/formats/webm/chromeos/webm_encoder.h b/media/formats/webm/chromeos/webm_encoder.h
new file mode 100644
index 0000000..fd0fc75
--- /dev/null
+++ b/media/formats/webm/chromeos/webm_encoder.h
@@ -0,0 +1,106 @@
+// 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.
+
+#ifndef MEDIA_FORMATS_WEBM_CHROMEOS_WEBM_ENCODER_H_
+#define MEDIA_FORMATS_WEBM_CHROMEOS_WEBM_ENCODER_H_
+
+#include <stdio.h>
+#include <stack>
+
+#include "base/files/file_path.h"
+#include "media/base/media_export.h"
+#include "media/formats/webm/chromeos/ebml_writer.h"
+
+extern "C" {
+#define VPX_CODEC_DISABLE_COMPAT 1
+#include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h"
+#include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
+}
+
+class SkBitmap;
+
+namespace base {
+class FilePath;
+}
+
+namespace media {
+
+namespace chromeos {
+
+// WebM encoder using libvpx. Currently only supports one-pass, constant bitrate
+// encoding of short files consisting of a single video track. Seek info and
+// cues are not supported, so generated .webm file does not strictly adhere to
+// WebM standard (http://www.webmproject.org/code/specs/container/).
+class MEDIA_EXPORT WebmEncoder {
+ public:
+ // Create new instance for writing to |output_path|. If |realtime| is |true|,
+ // uses realtime deadline, otherwise - "good quality" deadline.
+ WebmEncoder(const base::FilePath& output_path, int bitrate, bool realtime);
+ ~WebmEncoder();
+
+ // Encodes video from a Nx(N*M) sprite, having M frames of size NxN with FPS
+ // |fps_n/fps_d|. Must be called on a thread that allows disk IO.
+ // Returns |true| iff encoding and writing to file is successful.
+ bool EncodeFromSprite(const SkBitmap& sprite, int fps_n, int fps_d);
+
+ private:
+ // Writes global WebM header and starts a single video track. Returns |false|
+ // if there was an error opening file for writing.
+ bool WriteWebmHeader();
+
+ // Writes VPX packet to output file.
+ void WriteWebmBlock(const vpx_codec_cx_pkt_t* packet);
+
+ // Finishes video track and closes output file. Returns |false| if there were
+ // any error during encoding/writing file.
+ bool WriteWebmFooter();
+
+ // Starts a new WebM sub-element of given type. Those can be nested.
+ void StartSubElement(unsigned long class_id);
+
+ // Closes current top-level sub-element.
+ void EndSubElement();
+
+ // libmkv callbacks.
+ void EbmlWrite(const void* buffer, unsigned long len);
+ void EbmlSerialize(const void* buffer, int buffer_size, unsigned long len);
+
+ template <typename T>
+ void EbmlSerializeHelper(const T* buffer, unsigned long len);
+
+ // Video dimensions and FPS.
+ size_t width_;
+ size_t height_;
+ vpx_rational_t fps_;
+
+ // Number of frames in video.
+ size_t frame_count_;
+
+ // VPX config in use.
+ vpx_codec_enc_cfg_t config_;
+
+ // VPX parameters.
+ int bitrate_;
+ unsigned long deadline_;
+
+ // EbmlWriter context.
+ EbmlGlobal ebml_writer_;
+
+ // Stack with start offsets of currently open sub-elements.
+ std::stack<long int> ebml_sub_elements_;
+
+ base::FilePath output_path_;
+ FILE* output_;
+
+ // True if an error occured while encoding/writing to file.
+ bool has_errors_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebmEncoder);
+};
+
+} // namespace chromeos
+
+} // namespace media
+
+#endif // MEDIA_FORMATS_WEBM_CHROMEOS_WEBM_ENCODER_H_
diff --git a/media/media.gyp b/media/media.gyp
index 54bbabf..8ce7667 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -650,6 +650,19 @@
'DISABLE_USER_INPUT_MONITOR',
],
}],
+ # A simple WebM encoder for animated avatars on ChromeOS.
+ ['chromeos==1', {
+ 'dependencies': [
+ '../third_party/libvpx/libvpx.gyp:libvpx',
+ '../third_party/libyuv/libyuv.gyp:libyuv',
+ ],
+ 'sources': [
+ 'formats/webm/chromeos/ebml_writer.cc',
+ 'formats/webm/chromeos/ebml_writer.h',
+ 'formats/webm/chromeos/webm_encoder.cc',
+ 'formats/webm/chromeos/webm_encoder.h',
+ ],
+ }],
# For VaapiVideoEncodeAccelerator.
['target_arch != "arm" and chromeos == 1 and use_x11 == 1', {
'sources': [