diff options
author | johnme@chromium.org <johnme@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-22 14:44:22 +0000 |
---|---|---|
committer | johnme@chromium.org <johnme@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-22 14:44:22 +0000 |
commit | fe2e8506eb31302bd9ea251cba81b37cf6f9c2f6 (patch) | |
tree | aaab9b51f30ef464cdf9492b5ec69f5fcbbbd12f /media | |
parent | 49d75aea3cb6fbc29afa2b0b567ef5325b694ff5 (diff) | |
download | chromium_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.gn | 21 | ||||
-rw-r--r-- | media/formats/webm/chromeos/DEPS | 4 | ||||
-rw-r--r-- | media/formats/webm/chromeos/ebml_writer.cc | 33 | ||||
-rw-r--r-- | media/formats/webm/chromeos/ebml_writer.h | 21 | ||||
-rw-r--r-- | media/formats/webm/chromeos/webm_encoder.cc | 321 | ||||
-rw-r--r-- | media/formats/webm/chromeos/webm_encoder.h | 106 | ||||
-rw-r--r-- | media/media.gyp | 13 |
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': [ |