Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(888)

Unified Diff: ppapi/examples/video_encode/video_encode.cc

Issue 956893002: content: pepper: VideoEncoder: add software encoder support (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Another android dep fix Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/renderer/pepper/video_encoder_shim.cc ('k') | ppapi/examples/video_encode/video_encode.html » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ppapi/examples/video_encode/video_encode.cc
diff --git a/ppapi/examples/video_encode/video_encode.cc b/ppapi/examples/video_encode/video_encode.cc
index 26c66dff1fa34d7a8d30bf9619455843ffd17049..66d141a525648ef1551707440e20909ed560e721 100644
--- a/ppapi/examples/video_encode/video_encode.cc
+++ b/ppapi/examples/video_encode/video_encode.cc
@@ -7,6 +7,7 @@
#include <string.h>
#include <iostream>
+#include <map>
#include <sstream>
#include <vector>
@@ -24,9 +25,6 @@
#include "ppapi/cpp/video_frame.h"
#include "ppapi/utility/completion_callback_factory.h"
-// TODO(llandwerlin): turn on by default when we have software encode.
-// #define USE_VP8_INSTEAD_OF_H264
-
// When compiling natively on Windows, PostMessage can be #define-d to
// something else.
#ifdef PostMessage
@@ -39,52 +37,66 @@
#undef NDEBUG
#include <assert.h>
+#define fourcc(a, b, c, d) \
+ (((uint32_t)(a) << 0) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | \
+ ((uint32_t)(d) << 24))
+
namespace {
-std::string VideoProfileToString(PP_VideoProfile profile) {
- switch (profile) {
- case PP_VIDEOPROFILE_H264BASELINE:
- return "h264baseline";
- case PP_VIDEOPROFILE_H264MAIN:
- return "h264main";
- case PP_VIDEOPROFILE_H264EXTENDED:
- return "h264extended";
- case PP_VIDEOPROFILE_H264HIGH:
- return "h264high";
- case PP_VIDEOPROFILE_H264HIGH10PROFILE:
- return "h264high10";
- case PP_VIDEOPROFILE_H264HIGH422PROFILE:
- return "h264high422";
- case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE:
- return "h264high444predictive";
- case PP_VIDEOPROFILE_H264SCALABLEBASELINE:
- return "h264scalablebaseline";
- case PP_VIDEOPROFILE_H264SCALABLEHIGH:
- return "h264scalablehigh";
- case PP_VIDEOPROFILE_H264STEREOHIGH:
- return "h264stereohigh";
- case PP_VIDEOPROFILE_H264MULTIVIEWHIGH:
- return "h264multiviewhigh";
- case PP_VIDEOPROFILE_VP8_ANY:
- return "vp8";
- case PP_VIDEOPROFILE_VP9_ANY:
- return "vp9";
- // No default to catch unhandled profiles.
+// IVF container writer. It is possible to parse H264 bitstream using
+// NAL units but for VP8 we need a container to at least find encoded
+// pictures as well as the picture sizes.
+class IVFWriter {
+ public:
+ IVFWriter() {}
+ ~IVFWriter() {}
+
+ uint32_t GetFileHeaderSize() const { return 32; }
+ uint32_t GetFrameHeaderSize() const { return 12; }
+ uint32_t WriteFileHeader(uint8_t* mem, int32_t width, int32_t height);
+ uint32_t WriteFrameHeader(uint8_t* mem, uint64_t pts, size_t frame_size);
+
+ private:
+ void PutLE16(uint8_t* mem, int val) const {
+ mem[0] = (val >> 0) & 0xff;
+ mem[1] = (val >> 8) & 0xff;
}
- return "unknown";
-}
-
-std::string HardwareAccelerationToString(PP_HardwareAcceleration acceleration) {
- switch (acceleration) {
- case PP_HARDWAREACCELERATION_ONLY:
- return "hardware";
- case PP_HARDWAREACCELERATION_WITHFALLBACK:
- return "hardware/software";
- case PP_HARDWAREACCELERATION_NONE:
- return "software";
- // No default to catch unhandled accelerations.
+ void PutLE32(uint8_t* mem, int val) const {
+ mem[0] = (val >> 0) & 0xff;
+ mem[1] = (val >> 8) & 0xff;
+ mem[2] = (val >> 16) & 0xff;
+ mem[3] = (val >> 24) & 0xff;
}
- return "unknown";
+};
+
+uint32_t IVFWriter::WriteFileHeader(uint8_t* mem,
+ int32_t width,
+ int32_t height) {
+ mem[0] = 'D';
+ mem[1] = 'K';
+ mem[2] = 'I';
+ mem[3] = 'F';
+ PutLE16(mem + 4, 0); // version
+ PutLE16(mem + 6, 32); // header size
+ PutLE32(mem + 8, fourcc('V', 'P', '8', '0')); // fourcc
+ PutLE16(mem + 12, static_cast<uint16_t>(width)); // width
+ PutLE16(mem + 14, static_cast<uint16_t>(height)); // height
+ PutLE32(mem + 16, 30); // rate
+ PutLE32(mem + 20, 1); // scale
+ PutLE32(mem + 24, 0xffffffff); // length
+ PutLE32(mem + 28, 0); // unused
+
+ return 32;
+}
+
+uint32_t IVFWriter::WriteFrameHeader(uint8_t* mem,
+ uint64_t pts,
+ size_t frame_size) {
+ PutLE32(mem, (int)frame_size);
+ PutLE32(mem + 4, (int)(pts & 0xFFFFFFFF));
+ PutLE32(mem + 8, (int)(pts >> 32));
+
+ return 12;
}
// This object is the global object representing this plugin library as long
@@ -106,11 +118,17 @@ class VideoEncoderInstance : public pp::Instance {
virtual void HandleMessage(const pp::Var& var_message);
private:
+ void AddVideoProfile(PP_VideoProfile profile, const std::string& profile_str);
+ void InitializeVideoProfiles();
+ PP_VideoProfile VideoProfileFromString(const std::string& str);
+ std::string VideoProfileToString(PP_VideoProfile profile);
+
void ConfigureTrack();
void OnConfiguredTrack(int32_t result);
void ProbeEncoder();
void OnEncoderProbed(int32_t result,
const std::vector<PP_VideoProfileDescription> profiles);
+ void StartEncoder();
void OnInitializedEncoder(int32_t result);
void ScheduleNextEncode();
void GetEncoderFrameTick(int32_t result);
@@ -134,6 +152,12 @@ class VideoEncoderInstance : public pp::Instance {
void PostDataMessage(const void* buffer, uint32_t size);
void PostSignalMessage(const char* name);
+ typedef std::map<std::string, PP_VideoProfile> VideoProfileFromStringMap;
+ VideoProfileFromStringMap profile_from_string_;
+
+ typedef std::map<PP_VideoProfile, std::string> VideoProfileToStringMap;
+ VideoProfileToStringMap profile_to_string_;
+
bool is_encoding_;
bool is_receiving_track_frames_;
@@ -150,6 +174,8 @@ class VideoEncoderInstance : public pp::Instance {
uint32_t encoded_frames_;
pp::VideoFrame current_track_frame_;
+
+ IVFWriter ivf_writer_;
};
VideoEncoderInstance::VideoEncoderInstance(PP_Instance instance,
@@ -164,11 +190,52 @@ VideoEncoderInstance::VideoEncoderInstance(PP_Instance instance,
#endif
frame_format_(PP_VIDEOFRAME_FORMAT_I420),
encoded_frames_(0) {
+ InitializeVideoProfiles();
+ ProbeEncoder();
}
VideoEncoderInstance::~VideoEncoderInstance() {
}
+void VideoEncoderInstance::AddVideoProfile(PP_VideoProfile profile,
+ const std::string& profile_str) {
+ profile_to_string_.insert(std::make_pair(profile, profile_str));
+ profile_from_string_.insert(std::make_pair(profile_str, profile));
+}
+
+void VideoEncoderInstance::InitializeVideoProfiles() {
+ AddVideoProfile(PP_VIDEOPROFILE_H264BASELINE, "h264baseline");
+ AddVideoProfile(PP_VIDEOPROFILE_H264MAIN, "h264main");
+ AddVideoProfile(PP_VIDEOPROFILE_H264EXTENDED, "h264extended");
+ AddVideoProfile(PP_VIDEOPROFILE_H264HIGH, "h264high");
+ AddVideoProfile(PP_VIDEOPROFILE_H264HIGH10PROFILE, "h264high10");
+ AddVideoProfile(PP_VIDEOPROFILE_H264HIGH422PROFILE, "h264high422");
+ AddVideoProfile(PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE,
+ "h264high444predictive");
+ AddVideoProfile(PP_VIDEOPROFILE_H264SCALABLEBASELINE, "h264scalablebaseline");
+ AddVideoProfile(PP_VIDEOPROFILE_H264SCALABLEHIGH, "h264scalablehigh");
+ AddVideoProfile(PP_VIDEOPROFILE_H264STEREOHIGH, "h264stereohigh");
+ AddVideoProfile(PP_VIDEOPROFILE_H264MULTIVIEWHIGH, "h264multiviewhigh");
+ AddVideoProfile(PP_VIDEOPROFILE_VP8_ANY, "vp8");
+ AddVideoProfile(PP_VIDEOPROFILE_VP9_ANY, "vp9");
+}
+
+PP_VideoProfile VideoEncoderInstance::VideoProfileFromString(
+ const std::string& str) {
+ VideoProfileFromStringMap::iterator it = profile_from_string_.find(str);
+ if (it == profile_from_string_.end())
+ return PP_VIDEOPROFILE_VP8_ANY;
+ return it->second;
+}
+
+std::string VideoEncoderInstance::VideoProfileToString(
+ PP_VideoProfile profile) {
+ VideoProfileToStringMap::iterator it = profile_to_string_.find(profile);
+ if (it == profile_to_string_.end())
+ return "unknown";
+ return it->second;
+}
+
void VideoEncoderInstance::ConfigureTrack() {
if (encoder_size_.IsEmpty())
frame_size_ = requested_size_;
@@ -204,7 +271,7 @@ void VideoEncoderInstance::OnConfiguredTrack(int32_t result) {
StartTrackFrames();
ScheduleNextEncode();
} else
- ProbeEncoder();
+ StartEncoder();
}
void VideoEncoderInstance::ProbeEncoder() {
@@ -216,38 +283,25 @@ void VideoEncoderInstance::ProbeEncoder() {
void VideoEncoderInstance::OnEncoderProbed(
int32_t result,
const std::vector<PP_VideoProfileDescription> profiles) {
- bool has_required_profile = false;
+ pp::VarDictionary dict;
+ dict.Set(pp::Var("name"), pp::Var("supportedProfiles"));
+ pp::VarArray js_profiles;
+ dict.Set(pp::Var("profiles"), js_profiles);
- Log("Available profiles:");
- for (const PP_VideoProfileDescription& profile : profiles) {
- std::ostringstream oss;
- oss << " profile=" << VideoProfileToString(profile.profile)
- << " max_resolution=" << profile.max_resolution.width << "x"
- << profile.max_resolution.height
- << " max_framerate=" << profile.max_framerate_numerator << "/"
- << profile.max_framerate_denominator << " acceleration="
- << HardwareAccelerationToString(profile.acceleration);
- Log(oss.str());
-
- has_required_profile |= profile.profile == video_profile_;
+ if (result != PP_OK) {
+ LogError(result, "Cannot get supported profiles");
+ PostMessage(dict);
}
- if (!has_required_profile) {
- std::ostringstream oss;
- oss << "Cannot find required video profile: ";
- oss << VideoProfileToString(video_profile_);
- LogError(PP_ERROR_FAILED, oss.str());
- return;
- }
+ int32_t idx = 0;
+ for (const PP_VideoProfileDescription& profile : profiles)
+ js_profiles.Set(idx++, pp::Var(VideoProfileToString(profile.profile)));
+ PostMessage(dict);
+}
+void VideoEncoderInstance::StartEncoder() {
video_encoder_ = pp::VideoEncoder(this);
- pp::VarDictionary dict;
- dict.Set(pp::Var("status"), pp::Var("initializing encoder"));
- dict.Set(pp::Var("width"), pp::Var(encoder_size_.width()));
- dict.Set(pp::Var("height"), pp::Var(encoder_size_.height()));
- PostMessage(dict);
-
int32_t error = video_encoder_.Initialize(
frame_format_, frame_size_, video_profile_, 2000000,
PP_HARDWAREACCELERATION_WITHFALLBACK,
@@ -266,18 +320,13 @@ void VideoEncoderInstance::OnInitializedEncoder(int32_t result) {
}
is_encoding_ = true;
+ PostSignalMessage("started");
if (video_encoder_.GetFrameCodedSize(&encoder_size_) != PP_OK) {
LogError(result, "Cannot get encoder coded frame size");
return;
}
- pp::VarDictionary dict;
- dict.Set(pp::Var("status"), pp::Var("encoder initialized"));
- dict.Set(pp::Var("width"), pp::Var(encoder_size_.width()));
- dict.Set(pp::Var("height"), pp::Var(encoder_size_.height()));
- PostMessage(dict);
-
video_encoder_.GetBitstreamBuffer(callback_factory_.NewCallbackWithOutput(
&VideoEncoderInstance::OnGetBitstreamBuffer));
@@ -348,6 +397,7 @@ int32_t VideoEncoderInstance::CopyVideoFrame(pp::VideoFrame dest,
return PP_ERROR_FAILED;
}
+ dest.SetTimestamp(src.GetTimestamp());
memcpy(dest.GetDataBuffer(), src.GetDataBuffer(), src.GetDataBufferSize());
return PP_OK;
}
@@ -446,6 +496,8 @@ void VideoEncoderInstance::HandleMessage(const pp::Var& var_message) {
pp::Resource resource_track = var_track.AsResource();
video_track_ = pp::MediaStreamVideoTrack(resource_track);
video_encoder_ = pp::VideoEncoder();
+ video_profile_ = VideoProfileFromString(
+ dict_message.Get("profile").AsString());
ConfigureTrack();
} else if (command == "stop") {
StopEncode();
@@ -460,9 +512,34 @@ void VideoEncoderInstance::PostDataMessage(const void* buffer, uint32_t size) {
dictionary.Set(pp::Var("name"), pp::Var("data"));
- pp::VarArrayBuffer array_buffer(size);
- void* data_ptr = array_buffer.Map();
- memcpy(data_ptr, buffer, size);
+ pp::VarArrayBuffer array_buffer;
+ uint8_t* data_ptr;
+ uint32_t data_offset = 0;
+ if (video_profile_ == PP_VIDEOPROFILE_VP8_ANY ||
+ video_profile_ == PP_VIDEOPROFILE_VP9_ANY) {
+ uint32_t frame_offset = 0;
+ if (encoded_frames_ == 1) {
+ array_buffer = pp::VarArrayBuffer(
+ size + ivf_writer_.GetFileHeaderSize() +
+ ivf_writer_.GetFrameHeaderSize());
+ data_ptr = static_cast<uint8_t*>(array_buffer.Map());
+ frame_offset = ivf_writer_.WriteFileHeader(
+ data_ptr, frame_size_.width(), frame_size_.height());
+ } else {
+ array_buffer = pp::VarArrayBuffer(
+ size + ivf_writer_.GetFrameHeaderSize());
+ data_ptr = static_cast<uint8_t*>(array_buffer.Map());
+ }
+ data_offset = frame_offset +
+ ivf_writer_.WriteFrameHeader(data_ptr + frame_offset,
+ encoded_frames_,
+ size);
+ } else {
+ array_buffer = pp::VarArrayBuffer(size);
+ data_ptr = static_cast<uint8_t*>(array_buffer.Map());
+ }
+
+ memcpy(data_ptr + data_offset, buffer, size);
array_buffer.Unmap();
dictionary.Set(pp::Var("data"), array_buffer);
« no previous file with comments | « content/renderer/pepper/video_encoder_shim.cc ('k') | ppapi/examples/video_encode/video_encode.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698