summaryrefslogtreecommitdiffstats
blob: 40f631fbd97a75ce82f9439fa42a7ccbcb023811 (plain)
1
2
3
4
5
6
7
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
/*
 * Copyright (c) 2012 Yoann Blein
 * Licensed under the simplified BSD license.
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 */

#include <Swiften/ScreenSharing/VP8Decoder.h>

#include <Swiften/ScreenSharing/Image.h>
#include <Swiften/Base/Log.h>
#include "vpx/vp8dx.h"

namespace Swift {

inline int clamp8(int v)
{
	return std::min(std::max(v, 0), 255);
}

VP8Decoder::VP8Decoder()
	: VideoDecoder(),
	  codecInterface(vpx_codec_vp8_dx()), codecFlags(0)
{
	SWIFT_LOG(debug) << "VP8 Decoder:" << vpx_codec_iface_name(codecInterface) << std::endl;

	updateCodecConfig();
}

VP8Decoder::~VP8Decoder()
{
}

void VP8Decoder::updateCodecConfig()
{
	// TODO: vpx_codec_flags_t flags = VPX_CODEC_USE_INPUT_FRAGMENTS;
	vpx_codec_err_t err = vpx_codec_dec_init(&codecContext, codecInterface, NULL, codecFlags);
	if (err) {
		SWIFT_LOG(debug) << "VP8 Decoder: Failed to initialize decoder, " << vpx_codec_err_to_string(err) << std::endl;
		// TODO: exception ?
	}
}

void VP8Decoder::decodeFrame(const std::vector<uint8_t>& frame)
{
	// Decode the frame
	vpx_codec_err_t err = vpx_codec_decode(&codecContext, &frame[0], frame.size(), NULL, 0);
	if (err) {
		SWIFT_LOG(debug) << "VP8 Decoder: Failed to decode frame, " << vpx_codec_err_to_string(err) << std::endl;
		// TODO: exception ?
		return;
	}

	vpx_codec_iter_t iter = NULL;
	vpx_image_t* img;
	while ((img = vpx_codec_get_frame(&codecContext, &iter))) {
		Image rgbImg = convertYV12toRGB(img);
		onNewImageDecoded(rgbImg);
	}
}

Image VP8Decoder::convertYV12toRGB(const vpx_image_t* img)
{
	Image rgbImg(img->d_w, img->d_h);
	std::vector<uint8_t>& data = rgbImg.data;

	uint8_t *yPlane = img->planes[VPX_PLANE_Y];
	uint8_t *uPlane = img->planes[VPX_PLANE_U];
	uint8_t *vPlane = img->planes[VPX_PLANE_V];

	int i = 0;
	for (unsigned int imgY = 0; imgY < img->d_h; imgY++) {
		for (unsigned int imgX = 0; imgX < img->d_w; imgX++) {
			int y = yPlane[imgY * img->stride[VPX_PLANE_Y] + imgX];
			int u = uPlane[(imgY / 2) * img->stride[VPX_PLANE_U] + (imgX / 2)];
			int v = vPlane[(imgY / 2) * img->stride[VPX_PLANE_V] + (imgX / 2)];

			int c = y - 16;
			int d = (u - 128);
			int e = (v - 128);

			// TODO: adjust colors ?

			int r = clamp8((298 * c           + 409 * e + 128) >> 8);
			int g = clamp8((298 * c - 100 * d - 208 * e + 128) >> 8);
			int b = clamp8((298 * c + 516 * d           + 128) >> 8);

			// TODO: cast instead of clamp8

			data[i + 0] = static_cast<uint8_t>(r);
			data[i + 1] = static_cast<uint8_t>(g);
			data[i + 2] = static_cast<uint8_t>(b);

			i += 3;
		}
	}
	return rgbImg;
}

}