2014-11-23 15:49:23 +01:00
|
|
|
/*
|
|
|
|
|
Copyright 2014 Ahmet Inan <xdsopl@googlemail.com>
|
|
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
|
limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#pragma version(1)
|
|
|
|
|
#pragma rs java_package_name(xdsopl.robot36)
|
|
|
|
|
|
2014-11-30 12:29:30 +01:00
|
|
|
#include "complex.rsh"
|
2014-11-30 13:30:50 +01:00
|
|
|
#include "ema.rsh"
|
2014-11-30 17:02:51 +01:00
|
|
|
#include "ddc.rsh"
|
2014-11-30 17:18:17 +01:00
|
|
|
#include "fmd.rsh"
|
2014-11-30 18:58:19 +01:00
|
|
|
#include "scanline_estimator.rsh"
|
|
|
|
|
#include "calibration_detector.rsh"
|
|
|
|
|
#include "initialization.rsh"
|
|
|
|
|
#include "modes.rsh"
|
|
|
|
|
#include "constants.rsh"
|
|
|
|
|
#include "state.rsh"
|
2014-12-06 14:10:23 +01:00
|
|
|
#include "exports.rsh"
|
2014-12-08 23:03:26 +01:00
|
|
|
#include "blur.rsh"
|
2014-11-23 15:49:23 +01:00
|
|
|
|
|
|
|
|
static inline uchar4 rgb(uchar r, uchar g, uchar b) { return (uchar4){ b, g, r, 255 }; }
|
2014-12-05 15:53:13 +01:00
|
|
|
static inline uchar4 yuv(uchar y, uchar u, uchar v)
|
|
|
|
|
{
|
|
|
|
|
uchar4 bgra = rsYuvToRGBA_uchar4(y, u, v);
|
|
|
|
|
return rgb(bgra[0], bgra[1], bgra[2]);
|
|
|
|
|
}
|
2014-11-23 15:49:23 +01:00
|
|
|
|
2014-12-10 13:29:59 +01:00
|
|
|
static void reset_buffer()
|
2014-11-23 15:49:23 +01:00
|
|
|
{
|
|
|
|
|
vpos = 0;
|
2014-11-30 18:58:19 +01:00
|
|
|
hpos = 0;
|
2014-12-10 23:39:08 +01:00
|
|
|
prev_hpos = 0;
|
2014-11-23 15:49:23 +01:00
|
|
|
seperator_counter = 0;
|
2014-11-30 18:58:19 +01:00
|
|
|
sync_counter = sync_length;
|
2014-12-10 13:29:59 +01:00
|
|
|
buffer_cleared = 1;
|
|
|
|
|
for (int i = 0; i < maximum_width * maximum_height; ++i)
|
2014-11-30 18:58:19 +01:00
|
|
|
pixel_buffer[i] = rgb(0, 0, 0);
|
2014-11-23 15:49:23 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-10 13:29:59 +01:00
|
|
|
static void save_buffer()
|
|
|
|
|
{
|
2014-12-11 17:14:20 +01:00
|
|
|
free_running = 1;
|
2014-12-10 13:29:59 +01:00
|
|
|
if (!buffer_cleared)
|
|
|
|
|
return;
|
|
|
|
|
buffer_cleared = 0;
|
|
|
|
|
*saved_height = bitmap_height;
|
|
|
|
|
*saved_width = bitmap_width;
|
|
|
|
|
for (int i = 0; i < bitmap_width * bitmap_height; ++i)
|
|
|
|
|
saved_buffer[i] = pixel_buffer[i];
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-23 15:49:23 +01:00
|
|
|
static void robot36_decoder()
|
|
|
|
|
{
|
2014-11-25 20:38:07 +01:00
|
|
|
static prev_timeout;
|
2014-12-11 17:14:20 +01:00
|
|
|
if (free_running && !prev_timeout && 2 * abs(seperator_counter) > seperator_length)
|
2014-11-27 15:16:36 +01:00
|
|
|
vpos = (~1 & vpos) | (seperator_counter > 0);
|
2014-11-26 16:09:41 +01:00
|
|
|
prev_timeout = hpos >= maximum_length;
|
|
|
|
|
if (vpos & 1) {
|
2014-11-23 15:49:23 +01:00
|
|
|
for (int i = 0; i < bitmap_width; ++i) {
|
2014-12-11 14:17:24 +01:00
|
|
|
uchar even_y = value_blur(i, y_begin, y_end);
|
|
|
|
|
uchar v = value_blur(i, v_begin, v_end);
|
|
|
|
|
uchar odd_y = value_blur(i, prev_hpos + y_begin, prev_hpos + y_end);
|
|
|
|
|
uchar u = value_blur(i, prev_hpos + u_begin, prev_hpos + u_end);
|
2014-12-05 15:53:13 +01:00
|
|
|
pixel_buffer[bitmap_width * (vpos-1) + i] = yuv(even_y, u, v);
|
|
|
|
|
pixel_buffer[bitmap_width * vpos + i] = yuv(odd_y, u, v);
|
2014-11-23 15:49:23 +01:00
|
|
|
}
|
2014-11-25 20:38:07 +01:00
|
|
|
if (prev_timeout)
|
|
|
|
|
hpos -= scanline_length;
|
2014-11-25 18:24:51 +01:00
|
|
|
else
|
2014-11-25 20:38:07 +01:00
|
|
|
hpos = 0;
|
2014-12-10 23:39:08 +01:00
|
|
|
prev_hpos = 0;
|
2014-11-23 15:49:23 +01:00
|
|
|
} else {
|
2014-11-26 16:09:41 +01:00
|
|
|
if (prev_timeout) {
|
2014-12-10 23:39:08 +01:00
|
|
|
prev_hpos = scanline_length;
|
2014-11-26 16:09:41 +01:00
|
|
|
hpos -= scanline_length;
|
|
|
|
|
} else {
|
2014-12-10 23:39:08 +01:00
|
|
|
prev_hpos = hpos;
|
2014-11-26 16:09:41 +01:00
|
|
|
hpos = 0;
|
|
|
|
|
}
|
2014-11-23 15:49:23 +01:00
|
|
|
}
|
|
|
|
|
}
|
2014-11-30 18:58:19 +01:00
|
|
|
|
2014-11-23 15:49:23 +01:00
|
|
|
static void yuv_decoder()
|
|
|
|
|
{
|
2014-11-25 18:24:51 +01:00
|
|
|
for (int i = 0; i < bitmap_width; ++i) {
|
2014-12-11 14:17:24 +01:00
|
|
|
uchar y = value_blur(i, y_begin, y_end);
|
|
|
|
|
uchar u = value_blur(i, u_begin, u_end);
|
|
|
|
|
uchar v = value_blur(i, v_begin, v_end);
|
2014-12-05 15:53:13 +01:00
|
|
|
pixel_buffer[bitmap_width * vpos + i] = yuv(y, u, v);
|
2014-11-23 15:49:23 +01:00
|
|
|
}
|
2014-11-25 18:24:51 +01:00
|
|
|
if (hpos >= maximum_length)
|
2014-11-25 20:54:21 +01:00
|
|
|
hpos -= scanline_length;
|
2014-11-25 18:24:51 +01:00
|
|
|
else
|
2014-11-25 20:54:21 +01:00
|
|
|
hpos = 0;
|
2014-12-10 23:39:08 +01:00
|
|
|
prev_hpos = 0;
|
2014-11-23 15:49:23 +01:00
|
|
|
}
|
2014-11-30 18:58:19 +01:00
|
|
|
|
2014-11-23 15:49:23 +01:00
|
|
|
static void rgb_decoder()
|
|
|
|
|
{
|
2014-11-25 18:24:51 +01:00
|
|
|
for (int i = 0; i < bitmap_width; ++i) {
|
2014-12-11 14:17:24 +01:00
|
|
|
uchar r = value_blur(i, r_begin, r_end);
|
|
|
|
|
uchar g = value_blur(i, g_begin, g_end);
|
|
|
|
|
uchar b = value_blur(i, b_begin, b_end);
|
2014-11-23 15:49:23 +01:00
|
|
|
pixel_buffer[bitmap_width * vpos + i] = rgb(r, g, b);
|
|
|
|
|
}
|
2014-11-25 18:24:51 +01:00
|
|
|
if (hpos >= maximum_length)
|
2014-11-25 20:54:21 +01:00
|
|
|
hpos -= scanline_length;
|
2014-11-25 18:24:51 +01:00
|
|
|
else
|
2014-11-25 20:54:21 +01:00
|
|
|
hpos = 0;
|
2014-12-10 23:39:08 +01:00
|
|
|
prev_hpos = 0;
|
2014-11-23 15:49:23 +01:00
|
|
|
}
|
2014-11-30 18:58:19 +01:00
|
|
|
|
2014-11-23 15:49:23 +01:00
|
|
|
static void raw_decoder()
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < bitmap_width; ++i) {
|
2014-12-11 14:17:24 +01:00
|
|
|
uchar value = value_blur(i, 0, hpos);
|
2014-11-23 15:49:23 +01:00
|
|
|
pixel_buffer[bitmap_width * vpos + i] = rgb(value, value, value);
|
|
|
|
|
}
|
2014-12-10 23:39:08 +01:00
|
|
|
prev_hpos = hpos = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// don't you guys have anything better to do?
|
|
|
|
|
static void scottie_decoder()
|
|
|
|
|
{
|
|
|
|
|
if (!prev_hpos) {
|
|
|
|
|
for (int i = g_begin; i < g_end; ++i)
|
|
|
|
|
value_buffer[i + b_begin - g_begin] = value_buffer[i];
|
|
|
|
|
for (int i = r_begin; i < r_end; ++i)
|
|
|
|
|
value_buffer[i + g_begin - r_begin] = value_buffer[i];
|
|
|
|
|
prev_hpos = scanline_length;
|
|
|
|
|
hpos = 0;
|
|
|
|
|
// TODO: don't do this here ..
|
|
|
|
|
vpos = vpos < 0 ? vpos : vpos - 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < bitmap_width; ++i) {
|
2014-12-11 14:17:24 +01:00
|
|
|
uchar r = value_blur(i, prev_hpos + r_begin, prev_hpos + r_end);
|
|
|
|
|
uchar g = value_blur(i, g_begin, g_end);
|
|
|
|
|
uchar b = value_blur(i, b_begin, b_end);
|
2014-12-10 23:39:08 +01:00
|
|
|
pixel_buffer[bitmap_width * vpos + i] = rgb(r, g, b);
|
|
|
|
|
}
|
2014-12-10 23:42:50 +01:00
|
|
|
for (int i = 0; i < scanline_length; ++i)
|
2014-12-10 23:39:08 +01:00
|
|
|
value_buffer[i] = value_buffer[i + prev_hpos];
|
|
|
|
|
prev_hpos = scanline_length;
|
|
|
|
|
hpos = 0;
|
2014-11-23 15:49:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void decode(int samples) {
|
2014-12-10 13:29:59 +01:00
|
|
|
*saved_width = 0;
|
|
|
|
|
*saved_height = 0;
|
2014-11-23 15:49:23 +01:00
|
|
|
for (int sample = 0; sample < samples; ++sample) {
|
|
|
|
|
float amp = audio_buffer[sample] / 32768.0f;
|
|
|
|
|
float power = amp * amp;
|
2014-11-30 16:16:25 +01:00
|
|
|
if (filter(&avg_power, power) < 0.0000001f)
|
2014-11-23 15:49:23 +01:00
|
|
|
continue;
|
|
|
|
|
|
2014-11-30 17:02:51 +01:00
|
|
|
complex_t cnt_baseband = convert(&cnt_ddc, amp);
|
|
|
|
|
complex_t dat_baseband = convert(&dat_ddc, amp);
|
2014-11-23 15:49:23 +01:00
|
|
|
|
2014-11-30 17:18:17 +01:00
|
|
|
float cnt_value = demodulate(&cnt_fmd, cnt_baseband);
|
|
|
|
|
float dat_value = demodulate(&dat_fmd, dat_baseband);
|
2014-11-23 15:49:23 +01:00
|
|
|
|
2014-12-07 18:14:37 +01:00
|
|
|
int cnt_active = cabs(dat_baseband) < 4.0f * cabs(cnt_baseband);
|
|
|
|
|
int dat_active = cabs(cnt_baseband) < 4.0f * cabs(dat_baseband);
|
|
|
|
|
uchar cnt_level = save_cnt && cnt_active ? 127.5f - 127.5f * cnt_value : 0.0f;
|
|
|
|
|
uchar dat_level = save_dat && dat_active ? 127.5f + 127.5f * dat_value : 0.0f;
|
2014-12-10 23:39:08 +01:00
|
|
|
value_buffer[hpos + prev_hpos] = cnt_level | dat_level;
|
2014-11-23 15:49:23 +01:00
|
|
|
|
|
|
|
|
int cnt_quantized = round(cnt_value);
|
|
|
|
|
int dat_quantized = round(dat_value);
|
|
|
|
|
|
|
|
|
|
int sync_level = cnt_active && cnt_quantized == 0;
|
|
|
|
|
int sync_pulse = !sync_level && sync_counter >= sync_length;
|
|
|
|
|
sync_counter = sync_level ? sync_counter + 1 : 0;
|
|
|
|
|
|
2014-12-07 22:26:03 +01:00
|
|
|
if (*current_mode != mode_debug) {
|
2014-12-07 18:14:37 +01:00
|
|
|
int detected_mode = calibration_detector(dat_value, dat_active, cnt_active, cnt_quantized);
|
2014-12-11 17:14:20 +01:00
|
|
|
if (detected_mode >= 0) {
|
|
|
|
|
free_running = 0;
|
2014-12-10 13:29:59 +01:00
|
|
|
reset_buffer();
|
2014-12-11 17:14:20 +01:00
|
|
|
switch_mode(detected_mode);
|
|
|
|
|
}
|
2014-11-30 18:58:19 +01:00
|
|
|
int estimated_mode = scanline_estimator(sync_level);
|
2014-12-11 17:14:20 +01:00
|
|
|
if (estimated_mode >= 0 && estimated_mode != *current_mode) {
|
|
|
|
|
free_running = 1;
|
2014-12-10 13:29:59 +01:00
|
|
|
reset_buffer();
|
2014-12-11 17:14:20 +01:00
|
|
|
switch_mode(estimated_mode);
|
|
|
|
|
}
|
2014-11-28 23:22:30 +01:00
|
|
|
}
|
2014-11-28 23:08:16 +01:00
|
|
|
|
2014-11-26 16:09:41 +01:00
|
|
|
int u_sep = u_sep_begin <= hpos && hpos < u_sep_end;
|
|
|
|
|
int v_sep = v_sep_begin <= hpos && hpos < v_sep_end;
|
2014-11-23 15:49:23 +01:00
|
|
|
seperator_counter += (u_sep || v_sep) ? dat_quantized : 0;
|
|
|
|
|
|
2014-11-25 18:24:51 +01:00
|
|
|
if (++hpos >= maximum_length || sync_pulse) {
|
2014-11-25 15:37:58 +01:00
|
|
|
if (hpos < minimum_length) {
|
|
|
|
|
hpos = 0;
|
2014-12-10 23:39:08 +01:00
|
|
|
prev_hpos = 0;
|
2014-11-25 20:38:07 +01:00
|
|
|
seperator_counter = 0;
|
2014-11-25 15:37:58 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2014-12-07 22:26:03 +01:00
|
|
|
switch (current_decoder) {
|
|
|
|
|
case decoder_robot36:
|
2014-11-23 15:49:23 +01:00
|
|
|
robot36_decoder();
|
|
|
|
|
break;
|
2014-12-07 22:26:03 +01:00
|
|
|
case decoder_yuv:
|
2014-11-23 15:49:23 +01:00
|
|
|
yuv_decoder();
|
|
|
|
|
break;
|
2014-12-07 22:26:03 +01:00
|
|
|
case decoder_rgb:
|
2014-11-23 15:49:23 +01:00
|
|
|
rgb_decoder();
|
|
|
|
|
break;
|
2014-12-10 23:39:08 +01:00
|
|
|
case decoder_scottie:
|
|
|
|
|
scottie_decoder();
|
|
|
|
|
break;
|
2014-11-23 15:49:23 +01:00
|
|
|
default:
|
|
|
|
|
raw_decoder();
|
|
|
|
|
}
|
2014-12-10 13:29:59 +01:00
|
|
|
if (++vpos == bitmap_height)
|
|
|
|
|
save_buffer();
|
|
|
|
|
if (vpos >= maximum_height)
|
2014-11-23 15:49:23 +01:00
|
|
|
vpos = 0;
|
|
|
|
|
seperator_counter = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|