summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/ScreenSharing/VP8Encoder.cpp')
-rw-r--r--Swiften/ScreenSharing/VP8Encoder.cpp132
1 files changed, 132 insertions, 0 deletions
diff --git a/Swiften/ScreenSharing/VP8Encoder.cpp b/Swiften/ScreenSharing/VP8Encoder.cpp
new file mode 100644
index 0000000..20c73f9
--- /dev/null
+++ b/Swiften/ScreenSharing/VP8Encoder.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2012 Yoann Blein
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swiften/ScreenSharing/VP8Encoder.h>
+#include <Swiften/Base/Log.h>
+#include "vpx/vp8cx.h"
+
+namespace Swift {
+
+VP8Encoder::VP8Encoder(unsigned int width, unsigned int height) :
+ codecInterface(vpx_codec_vp8_cx()), imageBuffer(0), codecFlags(0), frameFlags(0), frameNumber(0)
+{
+ SWIFT_LOG(debug) << "VP8 Encoder:" << vpx_codec_iface_name(codecInterface) << std::endl;
+
+ // Populate encoder configuration
+ vpx_codec_err_t err = vpx_codec_enc_config_default(codecInterface, &codecConfig, 0);
+ if (err) {
+ SWIFT_LOG(debug) << "VP8 Encoder: Failed to get config, " << vpx_codec_err_to_string(err) << std::endl;
+ // TODO: exception
+ }
+
+ // Update the default configuration with our settings
+ codecConfig.rc_target_bitrate = width * height * codecConfig.rc_target_bitrate / codecConfig.g_w / codecConfig.g_h; // Sample config on VP8 doc
+ //codecConfig.rc_target_bitrate = 90000; // ?
+ codecConfig.g_w = width;
+ codecConfig.g_h = height;
+ //codecConfig.g_threads = ?;
+
+ // codecFlags = VPX_CODEC_USE_OUTPUT_PARTITION; // TODO: adapt packetization and decoder
+
+ updateCodecConfig(); // TODO: Handle and re-throw exceptions
+}
+
+VP8Encoder::~VP8Encoder()
+{
+ vpx_codec_destroy(&codecContext);
+ vpx_img_free(imageBuffer);
+}
+
+void VP8Encoder::updateCodecConfig()
+{
+ if (imageBuffer)
+ vpx_img_free(imageBuffer);
+
+ vpx_codec_err_t err = vpx_codec_enc_init(&codecContext, codecInterface, &codecConfig, codecFlags);
+ if (err) {
+ SWIFT_LOG(debug) << "VP8 Encoder: Failed to initialize encoder, " << vpx_codec_err_to_string(err) << std::endl;
+ // TODO: exception
+ }
+
+ imageBuffer = vpx_img_alloc(0, VPX_IMG_FMT_YV12, codecConfig.g_w, codecConfig.g_h, 1);
+ if (!imageBuffer) {
+ SWIFT_LOG(debug) << "VP8 Encoder: Failed to allocate image" << std::endl;
+ // TODO: exception
+ }
+}
+
+void VP8Encoder::encodingLoop()
+{
+ while (!stop) {
+ VideoFrame::ref frame = popWhenFrameIsAvailable();
+ if (stop)
+ return;
+
+ if (!convertRGB24toYV12inBuffer(frame)) {
+ SWIFT_LOG(debug) << "VP8 Encoder: Failed to convert frame: Image buffer not initialized" << std::endl;
+ return;
+ }
+
+ vpx_codec_err_t err = vpx_codec_encode(&codecContext, imageBuffer, frameNumber, 1, frameFlags, VPX_DL_REALTIME);
+ if (err) {
+ SWIFT_LOG(debug) << "VP8 Encoder: Failed to encode frame, " << vpx_codec_err_to_string(err) << std::endl;
+ // TODO: signal ?
+ return;
+ }
+
+ const vpx_codec_cx_pkt_t *pkt;
+ vpx_codec_iter_t iter = NULL;
+ while ((pkt = vpx_codec_get_cx_data(&codecContext, &iter))) {
+ switch (pkt->kind) {
+ case VPX_CODEC_CX_FRAME_PKT:
+ // TODO: Packetize this frame data
+ break;
+ default:
+ break;
+ }
+ }
+
+ ++frameNumber;
+ }
+}
+
+bool VP8Encoder::convertRGB24toYV12inBuffer(const VideoFrame::ref frame)
+{
+ if (!imageBuffer)
+ return false;
+
+ uint8_t *yPlane = imageBuffer->planes[VPX_PLANE_Y];
+ uint8_t *uPlane = imageBuffer->planes[VPX_PLANE_U];
+ uint8_t *vPlane = imageBuffer->planes[VPX_PLANE_V];
+
+ unsigned int width = frame->width;
+ unsigned int height = frame->height;
+ unsigned int len = width * height;
+ const std::vector<uint8_t> &data = frame->data;
+
+ for (unsigned int i = 0; i < len; ++i) {
+ yPlane[i] = data[i * 3];
+ }
+
+ for (unsigned int line = 0; line < height / 2; ++line) {
+ for (unsigned int col = 0; col < width / 2; ++col) {
+ const uint8_t *p1 = &data[3 * (2 * (line * width + col))];
+ const uint8_t *p2 = &data[3 * (2 * (line * width + col) + 1)];
+ const uint8_t *p3 = &data[3 * (2 * (line * width + col) + width)];
+ const uint8_t *p4 = &data[3 * (2 * (line * width + col) + width + 1)];
+
+ int r = (p1[0] + p2[0] + p3[0] + p4[0]) * 0.25;
+ int g = (p1[1] + p2[1] + p3[1] + p4[1]) * 0.25;
+ int b = (p1[2] + p2[2] + p3[2] + p4[2]) * 0.25;
+
+ uPlane[line * imageBuffer->stride[VPX_PLANE_U] + col] = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
+ vPlane[line * imageBuffer->stride[VPX_PLANE_V] + col] = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
+ }
+ }
+ return true;
+}
+
+}