mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-19 08:16:31 +00:00
Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b79b4fd55e | ||
|
|
6d77f5334f | ||
|
|
25957de017 | ||
|
|
847f34e10c | ||
|
|
0ab8e0d05e | ||
|
|
ac88996a8c | ||
|
|
408157c82b | ||
|
|
7356dea737 | ||
|
|
87a75a816a | ||
|
|
b6a2332207 | ||
|
|
34c0dcb1ce | ||
|
|
283f31a5a6 | ||
|
|
2f1264c916 | ||
|
|
69e7cbf746 | ||
|
|
05804e309f | ||
|
|
1d8c93d3ad | ||
|
|
f48695a04e | ||
|
|
8ac2fa201b | ||
|
|
2d9e51a1ca | ||
|
|
c4cf4f015b | ||
|
|
646afbffff | ||
|
|
6475eeef4c | ||
|
|
2e67a46eb8 | ||
|
|
c333e75dff | ||
|
|
72285023cb | ||
|
|
b00a6ffd8d | ||
|
|
ce935c431e | ||
|
|
ac0944ae1a | ||
|
|
66572806a2 | ||
|
|
a75d6487e3 | ||
|
|
897ad4951b | ||
|
|
e1ef86146f | ||
|
|
8f3a475a32 | ||
|
|
be5f63d64d | ||
|
|
40e17b05b3 | ||
|
|
0b8940d93d | ||
|
|
e92002c3d8 | ||
|
|
e558b0f1a1 | ||
|
|
b5784149b2 | ||
|
|
55b6a3e933 | ||
|
|
f7c2948477 | ||
|
|
c55b6c4d7d | ||
|
|
442790486c | ||
|
|
bbc7ceb110 | ||
|
|
2ffa561eb1 | ||
|
|
490d833983 | ||
|
|
0b3a1eb963 | ||
|
|
7fd5eb229f | ||
|
|
98b5e52a68 | ||
|
|
c8dc5119fe | ||
|
|
b556dfb897 | ||
|
|
06eda04180 | ||
|
|
05bba86c63 | ||
|
|
6827a72097 | ||
|
|
299b3886af | ||
|
|
f9bc5666b8 | ||
|
|
c9cb0a416e | ||
|
|
ffa68a86a6 | ||
|
|
8fe411aa8b | ||
|
|
36dd5d1533 | ||
|
|
33b9bff0b9 | ||
|
|
c24d6338e2 | ||
|
|
8cb6fc4e78 | ||
|
|
a9dfff84e6 | ||
|
|
988a91634a | ||
|
|
8f6df3b455 | ||
|
|
ef47fa4c74 | ||
|
|
f2f560a345 | ||
|
|
6a0ee68692 | ||
|
|
72741b90f4 | ||
|
|
0296ab60c3 | ||
|
|
77a53347c3 | ||
|
|
c32ea286f2 | ||
|
|
b2fb857f5b | ||
|
|
20cdabc8a4 | ||
|
|
e2f4c193e3 | ||
|
|
b4aa9593dc | ||
|
|
20c729893b | ||
|
|
a00f49331c | ||
|
|
85308e48fd | ||
|
|
ff08a0fb25 | ||
|
|
6145b69c97 | ||
|
|
cfc5ae1b94 | ||
|
|
54b221aabd | ||
|
|
dabee9d47a | ||
|
|
e30520d9f3 | ||
|
|
8f0acb2176 | ||
|
|
8edeff8160 | ||
|
|
cacec0d25c | ||
|
|
c54d7da19f | ||
|
|
df610e1045 | ||
|
|
8d4e6a13b0 | ||
|
|
c852e5f827 | ||
|
|
2a37f1650b | ||
|
|
15f160c874 | ||
|
|
df63ad4678 | ||
|
|
72cd61cccf | ||
|
|
3e5a444023 | ||
|
|
a3f4294cd8 | ||
|
|
d9401b70f5 | ||
|
|
4296d5dada | ||
|
|
12937b93d5 | ||
|
|
28cd5e5b87 | ||
|
|
7bacef7622 | ||
|
|
ca3638313b | ||
|
|
bb3e4ec2c7 | ||
|
|
d52ac784f6 | ||
|
|
f5a9214dd4 | ||
|
|
5b54a8dbe2 | ||
|
|
32165e97ed | ||
|
|
4b6f65881d | ||
|
|
0e7d8da407 | ||
|
|
1c862b21e9 | ||
|
|
b202438a4d | ||
|
|
50ee2ba964 | ||
|
|
9f40713ee1 | ||
|
|
5f393ae972 | ||
|
|
aca3ee9e23 |
@@ -1,7 +1,7 @@
|
||||
[bumpversion]
|
||||
commit = True
|
||||
tag = True
|
||||
current_version = 5.53
|
||||
current_version = 6.6
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
||||
serialize =
|
||||
{major}.{minor}
|
||||
|
||||
2
.github/workflows/docker-alpine-image.yaml
vendored
2
.github/workflows/docker-alpine-image.yaml
vendored
@@ -66,7 +66,7 @@ jobs:
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/arm64,linux/amd64,linux/arm/v7
|
||||
platforms: linux/arm64,linux/amd64,linux/arm/v6,linux/arm/v7
|
||||
file: pkg/docker/Dockerfile.alpine
|
||||
-
|
||||
name: Push
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -3,11 +3,12 @@
|
||||
/pkg/arch/pkg/
|
||||
/pkg/arch/src/
|
||||
/src/build/
|
||||
/python/build/
|
||||
/python/dist/
|
||||
/python/ustreamer.egg-info/
|
||||
/python/root/
|
||||
/janus/build/
|
||||
/ustreamer
|
||||
/ustreamer-dump
|
||||
/ustreamer-*
|
||||
/config.mk
|
||||
vgcore.*
|
||||
*.sock
|
||||
|
||||
21
Makefile
21
Makefile
@@ -9,6 +9,8 @@ PY ?= python3
|
||||
CFLAGS ?= -O3
|
||||
LDFLAGS ?=
|
||||
|
||||
R_DESTDIR = $(if $(DESTDIR),$(shell realpath "$(DESTDIR)"),)
|
||||
|
||||
export
|
||||
|
||||
_LINTERS_IMAGE ?= ustreamer-linters
|
||||
@@ -36,12 +38,14 @@ endif
|
||||
|
||||
apps:
|
||||
$(MAKE) -C src
|
||||
$(ECHO) ln -sf src/*.bin .
|
||||
for i in src/*.bin; do \
|
||||
test ! -x $$i || ln -sf $$i `basename $$i .bin`; \
|
||||
done
|
||||
|
||||
|
||||
python:
|
||||
$(MAKE) -C python
|
||||
$(ECHO) ln -sf python/build/lib.*/*.so .
|
||||
$(ECHO) ln -sf python/root/usr/lib/python*/site-packages/*.so .
|
||||
|
||||
|
||||
janus:
|
||||
@@ -57,10 +61,10 @@ endif
|
||||
ifneq ($(call optbool,$(WITH_JANUS)),)
|
||||
$(MAKE) -C janus install
|
||||
endif
|
||||
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
|
||||
mkdir -p $(R_DESTDIR)$(MANPREFIX)/man1
|
||||
for man in $(shell ls man); do \
|
||||
install -m644 man/$$man $(DESTDIR)$(MANPREFIX)/man1/$$man; \
|
||||
gzip -f $(DESTDIR)$(MANPREFIX)/man1/$$man; \
|
||||
install -m644 man/$$man $(R_DESTDIR)$(MANPREFIX)/man1/$$man; \
|
||||
gzip -f $(R_DESTDIR)$(MANPREFIX)/man1/$$man; \
|
||||
done
|
||||
|
||||
|
||||
@@ -69,9 +73,8 @@ install-strip: install
|
||||
|
||||
|
||||
regen:
|
||||
tools/$(MAKE)-jpeg-h.py src/ustreamer/data/blank.jpeg src/ustreamer/data/blank_jpeg.c BLANK
|
||||
tools/$(MAKE)-ico-h.py src/ustreamer/data/favicon.ico src/ustreamer/data/favicon_ico.c FAVICON
|
||||
tools/$(MAKE)-html-h.py src/ustreamer/data/index.html src/ustreamer/data/index_html.c INDEX
|
||||
tools/make-ico-h.py src/ustreamer/data/favicon.ico src/ustreamer/data/favicon_ico.c FAVICON
|
||||
tools/make-html-h.py src/ustreamer/data/index.html src/ustreamer/data/index_html.c INDEX
|
||||
|
||||
|
||||
release:
|
||||
@@ -118,7 +121,7 @@ clean-all: linters clean
|
||||
|
||||
clean:
|
||||
rm -rf pkg/arch/pkg pkg/arch/src pkg/arch/v*.tar.gz pkg/arch/ustreamer-*.pkg.tar.{xz,zst}
|
||||
rm -f *.bin *.so
|
||||
rm -f ustreamer ustreamer-* *.so
|
||||
$(MAKE) -C src clean
|
||||
$(MAKE) -C python clean
|
||||
$(MAKE) -C janus clean
|
||||
|
||||
@@ -85,13 +85,13 @@ Without arguments, ```ustreamer``` will try to open ```/dev/video0``` with 640x4
|
||||
|
||||
:exclamation: Please note that since µStreamer v2.0 cross-domain requests were disabled by default for [security reasons](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). To enable the old behavior, use the option `--allow-origin=\*`.
|
||||
|
||||
The recommended way of running µStreamer with [Auvidea B101](https://www.raspberrypi.org/forums/viewtopic.php?f=38&t=120702&start=400#p1339178) on Raspberry Pi:
|
||||
The recommended way of running µStreamer with [TC358743-based capture device](https://www.raspberrypi.org/forums/viewtopic.php?f=38&t=120702&start=400#p1339178) on Raspberry Pi:
|
||||
```
|
||||
$ ./ustreamer \
|
||||
--format=uyvy \ # Device input format
|
||||
--encoder=m2m-image \ # Hardware encoding on V4L2 M2M driver
|
||||
--workers=3 \ # Workers number
|
||||
--persistent \ # Don't re-initialize device on timeout (for example when HDMI cable was disconnected)
|
||||
--persistent \ # Suppress repetitive signal source errors (for example when HDMI cable was disconnected)
|
||||
--dv-timings \ # Use DV-timings
|
||||
--drop-same-frames=30 # Save the traffic
|
||||
```
|
||||
@@ -209,7 +209,7 @@ v4l2 utilities provide the tools to manage USB webcam setting and information. S
|
||||
|
||||
-----
|
||||
# License
|
||||
Copyright (C) 2018-2023 by Maxim Devaev mdevaev@gmail.com
|
||||
Copyright (C) 2018-2024 by Maxim Devaev mdevaev@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
DESTDIR ?=
|
||||
R_DESTDIR ?=
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
CC ?= gcc
|
||||
@@ -42,8 +42,8 @@ $(_BUILD)/%.o: %.c
|
||||
|
||||
|
||||
install: $(_PLUGIN)
|
||||
mkdir -p $(DESTDIR)$(PREFIX)/lib/ustreamer/janus
|
||||
install -m755 $(_PLUGIN) $(DESTDIR)$(PREFIX)/lib/ustreamer/janus/$(PLUGIN)
|
||||
mkdir -p $(R_DESTDIR)$(PREFIX)/lib/ustreamer/janus
|
||||
install -m755 $(_PLUGIN) $(R_DESTDIR)$(PREFIX)/lib/ustreamer/janus/$(PLUGIN)
|
||||
|
||||
|
||||
clean:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -22,6 +22,23 @@
|
||||
|
||||
#include "audio.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdatomic.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <speex/speex_resampler.h>
|
||||
#include <opus/opus.h>
|
||||
|
||||
#include "uslibs/types.h"
|
||||
#include "uslibs/tools.h"
|
||||
#include "uslibs/array.h"
|
||||
#include "uslibs/ring.h"
|
||||
#include "uslibs/threading.h"
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
|
||||
#define _JLOG_PERROR_ALSA(_err, _prefix, _msg, ...) US_JLOG_ERROR(_prefix, _msg ": %s", ##__VA_ARGS__, snd_strerror(_err))
|
||||
#define _JLOG_PERROR_RES(_err, _prefix, _msg, ...) US_JLOG_ERROR(_prefix, _msg ": %s", ##__VA_ARGS__, speex_resampler_strerror(_err))
|
||||
@@ -31,7 +48,7 @@
|
||||
// - https://github.com/xiph/opus/blob/7b05f44/src/opus_demo.c#L368
|
||||
#define _HZ_TO_FRAMES(_hz) (6 * (_hz) / 50) // 120ms
|
||||
#define _HZ_TO_BUF16(_hz) (_HZ_TO_FRAMES(_hz) * 2) // One stereo frame = (16bit L) + (16bit R)
|
||||
#define _HZ_TO_BUF8(_hz) (_HZ_TO_BUF16(_hz) * sizeof(int16_t))
|
||||
#define _HZ_TO_BUF8(_hz) (_HZ_TO_BUF16(_hz) * sizeof(s16))
|
||||
|
||||
#define _MIN_PCM_HZ 8000
|
||||
#define _MAX_PCM_HZ 192000
|
||||
@@ -41,16 +58,19 @@
|
||||
|
||||
|
||||
typedef struct {
|
||||
int16_t data[_MAX_BUF16];
|
||||
s16 data[_MAX_BUF16];
|
||||
} _pcm_buffer_s;
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[_MAX_BUF8]; // Worst case
|
||||
size_t used;
|
||||
uint64_t pts;
|
||||
u8 data[_MAX_BUF8]; // Worst case
|
||||
uz used;
|
||||
u64 pts;
|
||||
} _enc_buffer_s;
|
||||
|
||||
|
||||
static _pcm_buffer_s *_pcm_buffer_init(void);
|
||||
static _enc_buffer_s *_enc_buffer_init(void);
|
||||
|
||||
static void *_pcm_thread(void *v_audio);
|
||||
static void *_encoder_thread(void *v_audio);
|
||||
|
||||
@@ -68,12 +88,12 @@ bool us_audio_probe(const char *name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
us_audio_s *us_audio_init(const char *name, unsigned pcm_hz) {
|
||||
us_audio_s *us_audio_init(const char *name, uint pcm_hz) {
|
||||
us_audio_s *audio;
|
||||
US_CALLOC(audio, 1);
|
||||
audio->pcm_hz = pcm_hz;
|
||||
audio->pcm_queue = us_queue_init(8);
|
||||
audio->enc_queue = us_queue_init(8);
|
||||
US_RING_INIT_WITH_ITEMS(audio->pcm_ring, 8, _pcm_buffer_init);
|
||||
US_RING_INIT_WITH_ITEMS(audio->enc_ring, 8, _enc_buffer_init);
|
||||
atomic_init(&audio->stop, false);
|
||||
|
||||
int err;
|
||||
@@ -151,38 +171,51 @@ void us_audio_destroy(us_audio_s *audio) {
|
||||
US_DELETE(audio->res, speex_resampler_destroy);
|
||||
US_DELETE(audio->pcm, snd_pcm_close);
|
||||
US_DELETE(audio->pcm_params, snd_pcm_hw_params_free);
|
||||
US_QUEUE_DELETE_WITH_ITEMS(audio->enc_queue, free);
|
||||
US_QUEUE_DELETE_WITH_ITEMS(audio->pcm_queue, free);
|
||||
US_RING_DELETE_WITH_ITEMS(audio->enc_ring, free);
|
||||
US_RING_DELETE_WITH_ITEMS(audio->pcm_ring, free);
|
||||
if (audio->tids_created) {
|
||||
US_JLOG_INFO("audio", "Pipeline closed");
|
||||
}
|
||||
free(audio);
|
||||
}
|
||||
|
||||
int us_audio_get_encoded(us_audio_s *audio, uint8_t *data, size_t *size, uint64_t *pts) {
|
||||
int us_audio_get_encoded(us_audio_s *audio, u8 *data, uz *size, u64 *pts) {
|
||||
if (atomic_load(&audio->stop)) {
|
||||
return -1;
|
||||
}
|
||||
_enc_buffer_s *buf;
|
||||
if (!us_queue_get(audio->enc_queue, (void **)&buf, 0.1)) {
|
||||
if (*size < buf->used) {
|
||||
free(buf);
|
||||
return -3;
|
||||
}
|
||||
memcpy(data, buf->data, buf->used);
|
||||
*size = buf->used;
|
||||
*pts = buf->pts;
|
||||
free(buf);
|
||||
return 0;
|
||||
const int ri = us_ring_consumer_acquire(audio->enc_ring, 0.1);
|
||||
if (ri < 0) {
|
||||
return -2;
|
||||
}
|
||||
return -2;
|
||||
const _enc_buffer_s *const buf = audio->enc_ring->items[ri];
|
||||
if (*size < buf->used) {
|
||||
us_ring_consumer_release(audio->enc_ring, ri);
|
||||
return -3;
|
||||
}
|
||||
memcpy(data, buf->data, buf->used);
|
||||
*size = buf->used;
|
||||
*pts = buf->pts;
|
||||
us_ring_consumer_release(audio->enc_ring, ri);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static _pcm_buffer_s *_pcm_buffer_init(void) {
|
||||
_pcm_buffer_s *buf;
|
||||
US_CALLOC(buf, 1);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static _enc_buffer_s *_enc_buffer_init(void) {
|
||||
_enc_buffer_s *buf;
|
||||
US_CALLOC(buf, 1);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void *_pcm_thread(void *v_audio) {
|
||||
US_THREAD_RENAME("us_a_pcm");
|
||||
US_THREAD_SETTLE("us_a_pcm");
|
||||
|
||||
us_audio_s *const audio = (us_audio_s *)v_audio;
|
||||
uint8_t in[_MAX_BUF8];
|
||||
us_audio_s *const audio = v_audio;
|
||||
u8 in[_MAX_BUF8];
|
||||
|
||||
while (!atomic_load(&audio->stop)) {
|
||||
const int frames = snd_pcm_readi(audio->pcm, in, audio->pcm_frames);
|
||||
@@ -194,13 +227,13 @@ static void *_pcm_thread(void *v_audio) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (us_queue_get_free(audio->pcm_queue)) {
|
||||
_pcm_buffer_s *out;
|
||||
US_CALLOC(out, 1);
|
||||
const int ri = us_ring_producer_acquire(audio->pcm_ring, 0);
|
||||
if (ri >= 0) {
|
||||
_pcm_buffer_s *const out = audio->pcm_ring->items[ri];
|
||||
memcpy(out->data, in, audio->pcm_size);
|
||||
assert(!us_queue_put(audio->pcm_queue, out, 0));
|
||||
us_ring_producer_release(audio->pcm_ring, ri);
|
||||
} else {
|
||||
US_JLOG_ERROR("audio", "PCM queue is full");
|
||||
US_JLOG_ERROR("audio", "PCM ring is full");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,45 +242,50 @@ static void *_pcm_thread(void *v_audio) {
|
||||
}
|
||||
|
||||
static void *_encoder_thread(void *v_audio) {
|
||||
US_THREAD_RENAME("us_a_enc");
|
||||
US_THREAD_SETTLE("us_a_enc");
|
||||
|
||||
us_audio_s *const audio = (us_audio_s *)v_audio;
|
||||
int16_t in_res[_MAX_BUF16];
|
||||
us_audio_s *const audio = v_audio;
|
||||
s16 in_res[_MAX_BUF16];
|
||||
|
||||
while (!atomic_load(&audio->stop)) {
|
||||
_pcm_buffer_s *in;
|
||||
if (!us_queue_get(audio->pcm_queue, (void **)&in, 0.1)) {
|
||||
int16_t *in_ptr;
|
||||
if (audio->res != NULL) {
|
||||
assert(audio->pcm_hz != _ENCODER_INPUT_HZ);
|
||||
uint32_t in_count = audio->pcm_frames;
|
||||
uint32_t out_count = _HZ_TO_FRAMES(_ENCODER_INPUT_HZ);
|
||||
speex_resampler_process_interleaved_int(audio->res, in->data, &in_count, in_res, &out_count);
|
||||
in_ptr = in_res;
|
||||
} else {
|
||||
assert(audio->pcm_hz == _ENCODER_INPUT_HZ);
|
||||
in_ptr = in->data;
|
||||
}
|
||||
const int in_ri = us_ring_consumer_acquire(audio->pcm_ring, 0.1);
|
||||
if (in_ri < 0) {
|
||||
continue;
|
||||
}
|
||||
_pcm_buffer_s *const in = audio->pcm_ring->items[in_ri];
|
||||
|
||||
_enc_buffer_s *out;
|
||||
US_CALLOC(out, 1);
|
||||
const int size = opus_encode(audio->enc, in_ptr, _HZ_TO_FRAMES(_ENCODER_INPUT_HZ), out->data, US_ARRAY_LEN(out->data));
|
||||
free(in);
|
||||
if (size < 0) {
|
||||
_JLOG_PERROR_OPUS(size, "audio", "Fatal: Can't encode PCM frame to OPUS");
|
||||
free(out);
|
||||
break;
|
||||
}
|
||||
s16 *in_ptr;
|
||||
if (audio->res != NULL) {
|
||||
assert(audio->pcm_hz != _ENCODER_INPUT_HZ);
|
||||
u32 in_count = audio->pcm_frames;
|
||||
u32 out_count = _HZ_TO_FRAMES(_ENCODER_INPUT_HZ);
|
||||
speex_resampler_process_interleaved_int(audio->res, in->data, &in_count, in_res, &out_count);
|
||||
in_ptr = in_res;
|
||||
} else {
|
||||
assert(audio->pcm_hz == _ENCODER_INPUT_HZ);
|
||||
in_ptr = in->data;
|
||||
}
|
||||
|
||||
const int out_ri = us_ring_producer_acquire(audio->enc_ring, 0);
|
||||
if (out_ri < 0) {
|
||||
US_JLOG_ERROR("audio", "OPUS encoder queue is full");
|
||||
us_ring_consumer_release(audio->pcm_ring, in_ri);
|
||||
continue;
|
||||
}
|
||||
_enc_buffer_s *const out = audio->enc_ring->items[out_ri];
|
||||
|
||||
const int size = opus_encode(audio->enc, in_ptr, _HZ_TO_FRAMES(_ENCODER_INPUT_HZ), out->data, US_ARRAY_LEN(out->data));
|
||||
us_ring_consumer_release(audio->pcm_ring, in_ri);
|
||||
|
||||
if (size >= 0) {
|
||||
out->used = size;
|
||||
out->pts = audio->pts;
|
||||
// https://datatracker.ietf.org/doc/html/rfc7587#section-4.2
|
||||
audio->pts += _HZ_TO_FRAMES(_ENCODER_INPUT_HZ);
|
||||
|
||||
if (us_queue_put(audio->enc_queue, out, 0) != 0) {
|
||||
US_JLOG_ERROR("audio", "OPUS encoder queue is full");
|
||||
free(out);
|
||||
}
|
||||
} else {
|
||||
_JLOG_PERROR_OPUS(size, "audio", "Fatal: Can't encode PCM frame to OPUS");
|
||||
}
|
||||
us_ring_producer_release(audio->enc_ring, out_ri);
|
||||
}
|
||||
|
||||
atomic_store(&audio->stop, true);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -22,50 +22,40 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdatomic.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <speex/speex_resampler.h>
|
||||
#include <opus/opus.h>
|
||||
|
||||
#include "uslibs/tools.h"
|
||||
#include "uslibs/array.h"
|
||||
#include "uslibs/threading.h"
|
||||
|
||||
#include "logging.h"
|
||||
#include "queue.h"
|
||||
#include "uslibs/types.h"
|
||||
#include "uslibs/ring.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
snd_pcm_t *pcm;
|
||||
unsigned pcm_hz;
|
||||
unsigned pcm_frames;
|
||||
size_t pcm_size;
|
||||
uint pcm_hz;
|
||||
uint pcm_frames;
|
||||
uz pcm_size;
|
||||
snd_pcm_hw_params_t *pcm_params;
|
||||
SpeexResamplerState *res;
|
||||
OpusEncoder *enc;
|
||||
|
||||
us_queue_s *pcm_queue;
|
||||
us_queue_s *enc_queue;
|
||||
uint32_t pts;
|
||||
us_ring_s *pcm_ring;
|
||||
us_ring_s *enc_ring;
|
||||
u32 pts;
|
||||
|
||||
pthread_t pcm_tid;
|
||||
pthread_t enc_tid;
|
||||
bool tids_created;
|
||||
atomic_bool stop;
|
||||
pthread_t pcm_tid;
|
||||
pthread_t enc_tid;
|
||||
bool tids_created;
|
||||
atomic_bool stop;
|
||||
} us_audio_s;
|
||||
|
||||
|
||||
bool us_audio_probe(const char *name);
|
||||
|
||||
us_audio_s *us_audio_init(const char *name, unsigned pcm_hz);
|
||||
us_audio_s *us_audio_init(const char *name, uint pcm_hz);
|
||||
void us_audio_destroy(us_audio_s *audio);
|
||||
|
||||
int us_audio_get_encoded(us_audio_s *audio, uint8_t *data, size_t *size, uint64_t *pts);
|
||||
int us_audio_get_encoded(us_audio_s *audio, u8 *data, uz *size, u64 *pts);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -33,9 +33,9 @@
|
||||
#include "uslibs/tools.h"
|
||||
#include "uslibs/threading.h"
|
||||
#include "uslibs/list.h"
|
||||
#include "uslibs/ring.h"
|
||||
|
||||
#include "logging.h"
|
||||
#include "queue.h"
|
||||
#include "rtp.h"
|
||||
|
||||
|
||||
@@ -51,13 +51,14 @@ us_janus_client_s *us_janus_client_init(janus_callbacks *gw, janus_plugin_sessio
|
||||
client->session = session;
|
||||
atomic_init(&client->transmit, false);
|
||||
atomic_init(&client->transmit_audio, false);
|
||||
atomic_init(&client->video_orient, 0);
|
||||
|
||||
atomic_init(&client->stop, false);
|
||||
|
||||
client->video_queue = us_queue_init(2048);
|
||||
US_RING_INIT_WITH_ITEMS(client->video_ring, 2048, us_rtp_init);
|
||||
US_THREAD_CREATE(client->video_tid, _video_thread, client);
|
||||
|
||||
client->audio_queue = us_queue_init(64);
|
||||
US_RING_INIT_WITH_ITEMS(client->audio_ring, 64, us_rtp_init);
|
||||
US_THREAD_CREATE(client->audio_tid, _audio_thread, client);
|
||||
|
||||
return client;
|
||||
@@ -65,14 +66,12 @@ us_janus_client_s *us_janus_client_init(janus_callbacks *gw, janus_plugin_sessio
|
||||
|
||||
void us_janus_client_destroy(us_janus_client_s *client) {
|
||||
atomic_store(&client->stop, true);
|
||||
us_queue_put(client->video_queue, NULL, 0);
|
||||
us_queue_put(client->audio_queue, NULL, 0);
|
||||
|
||||
US_THREAD_JOIN(client->video_tid);
|
||||
US_QUEUE_DELETE_WITH_ITEMS(client->video_queue, us_rtp_destroy);
|
||||
US_RING_DELETE_WITH_ITEMS(client->video_ring, us_rtp_destroy);
|
||||
|
||||
US_THREAD_JOIN(client->audio_tid);
|
||||
US_QUEUE_DELETE_WITH_ITEMS(client->audio_queue, us_rtp_destroy);
|
||||
US_RING_DELETE_WITH_ITEMS(client->audio_ring, us_rtp_destroy);
|
||||
|
||||
free(client);
|
||||
}
|
||||
@@ -82,64 +81,77 @@ void us_janus_client_send(us_janus_client_s *client, const us_rtp_s *rtp) {
|
||||
atomic_load(&client->transmit)
|
||||
&& (rtp->video || atomic_load(&client->transmit_audio))
|
||||
) {
|
||||
us_rtp_s *const new = us_rtp_dup(rtp);
|
||||
if (us_queue_put((new->video ? client->video_queue : client->audio_queue), new, 0) != 0) {
|
||||
US_JLOG_ERROR("client", "Session %p %s queue is full",
|
||||
client->session, (new->video ? "video" : "audio"));
|
||||
us_rtp_destroy(new);
|
||||
us_ring_s *const ring = (rtp->video ? client->video_ring : client->audio_ring);
|
||||
const int ri = us_ring_producer_acquire(ring, 0);
|
||||
if (ri < 0) {
|
||||
US_JLOG_ERROR("client", "Session %p %s ring is full",
|
||||
client->session, (rtp->video ? "video" : "audio"));
|
||||
return;
|
||||
}
|
||||
memcpy(ring->items[ri], rtp, sizeof(us_rtp_s));
|
||||
us_ring_producer_release(ring, ri);
|
||||
}
|
||||
}
|
||||
|
||||
static void *_video_thread(void *v_client) {
|
||||
US_THREAD_SETTLE("us_c_video");
|
||||
return _common_thread(v_client, true);
|
||||
}
|
||||
|
||||
static void *_audio_thread(void *v_client) {
|
||||
US_THREAD_SETTLE("us_c_audio");
|
||||
return _common_thread(v_client, false);
|
||||
}
|
||||
|
||||
static void *_common_thread(void *v_client, bool video) {
|
||||
us_janus_client_s *const client = (us_janus_client_s *)v_client;
|
||||
us_queue_s *const queue = (video ? client->video_queue : client->audio_queue);
|
||||
assert(queue != NULL); // Audio may be NULL
|
||||
us_janus_client_s *const client = v_client;
|
||||
us_ring_s *const ring = (video ? client->video_ring : client->audio_ring);
|
||||
assert(ring != NULL); // Audio may be NULL
|
||||
|
||||
while (!atomic_load(&client->stop)) {
|
||||
us_rtp_s *rtp;
|
||||
if (!us_queue_get(queue, (void **)&rtp, 0.1)) {
|
||||
if (rtp == NULL) {
|
||||
break;
|
||||
const int ri = us_ring_consumer_acquire(ring, 0.1);
|
||||
if (ri < 0) {
|
||||
continue;
|
||||
}
|
||||
us_rtp_s rtp;
|
||||
memcpy(&rtp, ring->items[ri], sizeof(us_rtp_s));
|
||||
us_ring_consumer_release(ring, ri);
|
||||
|
||||
if (
|
||||
atomic_load(&client->transmit)
|
||||
&& (video || atomic_load(&client->transmit_audio))
|
||||
) {
|
||||
janus_plugin_rtp packet = {
|
||||
.video = rtp.video,
|
||||
.buffer = (char*)rtp.datagram,
|
||||
.length = rtp.used,
|
||||
# if JANUS_PLUGIN_API_VERSION >= 100
|
||||
// The uStreamer Janus plugin places video in stream index 0 and audio
|
||||
// (if available) in stream index 1.
|
||||
.mindex = (rtp.video ? 0 : 1),
|
||||
# endif
|
||||
};
|
||||
janus_plugin_rtp_extensions_reset(&packet.extensions);
|
||||
|
||||
/*if (rtp->zero_playout_delay) {
|
||||
// https://github.com/pikvm/pikvm/issues/784
|
||||
packet.extensions.min_delay = 0;
|
||||
packet.extensions.max_delay = 0;
|
||||
} else {
|
||||
packet.extensions.min_delay = 0;
|
||||
// 10s - Chromium/WebRTC default
|
||||
// 3s - Firefox default
|
||||
packet.extensions.max_delay = 300; // == 3s, i.e. 10ms granularity
|
||||
}*/
|
||||
|
||||
if (rtp.video) {
|
||||
const uint video_orient = atomic_load(&client->video_orient);
|
||||
if (video_orient != 0) {
|
||||
packet.extensions.video_rotation = video_orient;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
atomic_load(&client->transmit)
|
||||
&& (video || atomic_load(&client->transmit_audio))
|
||||
) {
|
||||
janus_plugin_rtp packet = {
|
||||
.video = rtp->video,
|
||||
.buffer = (char *)rtp->datagram,
|
||||
.length = rtp->used,
|
||||
# if JANUS_PLUGIN_API_VERSION >= 100
|
||||
// The uStreamer Janus plugin places video in stream index 0 and audio
|
||||
// (if available) in stream index 1.
|
||||
.mindex = (rtp->video ? 0 : 1),
|
||||
# endif
|
||||
};
|
||||
janus_plugin_rtp_extensions_reset(&packet.extensions);
|
||||
/*if (rtp->zero_playout_delay) {
|
||||
// https://github.com/pikvm/pikvm/issues/784
|
||||
packet.extensions.min_delay = 0;
|
||||
packet.extensions.max_delay = 0;
|
||||
} else {
|
||||
packet.extensions.min_delay = 0;
|
||||
// 10s - Chromium/WebRTC default
|
||||
// 3s - Firefox default
|
||||
packet.extensions.max_delay = 300; // == 3s, i.e. 10ms granularity
|
||||
}*/
|
||||
|
||||
client->gw->relay_rtp(client->session, &packet);
|
||||
}
|
||||
us_rtp_destroy(rtp);
|
||||
client->gw->relay_rtp(client->session, &packet);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -29,8 +29,8 @@
|
||||
|
||||
#include "uslibs/types.h"
|
||||
#include "uslibs/list.h"
|
||||
#include "uslibs/ring.h"
|
||||
|
||||
#include "queue.h"
|
||||
#include "rtp.h"
|
||||
|
||||
|
||||
@@ -39,13 +39,14 @@ typedef struct us_janus_client_sx {
|
||||
janus_plugin_session *session;
|
||||
atomic_bool transmit;
|
||||
atomic_bool transmit_audio;
|
||||
atomic_uint video_orient;
|
||||
|
||||
pthread_t video_tid;
|
||||
pthread_t audio_tid;
|
||||
atomic_bool stop;
|
||||
|
||||
us_queue_s *video_queue;
|
||||
us_queue_s *audio_queue;
|
||||
us_ring_s *video_ring;
|
||||
us_ring_s *audio_ring;
|
||||
|
||||
US_LIST_STRUCT(struct us_janus_client_sx);
|
||||
} us_janus_client_s;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -36,11 +36,3 @@
|
||||
JANUS_LOG(LOG_ERR, "[%s/%-9s] " x_msg ": %s\n", US_PLUGIN_NAME, x_prefix, ##__VA_ARGS__, m_perror_str); \
|
||||
free(m_perror_str); \
|
||||
}
|
||||
|
||||
#define US_ONCE(...) { \
|
||||
const int m_reported = __LINE__; \
|
||||
if (m_reported != once) { \
|
||||
__VA_ARGS__; \
|
||||
once = m_reported; \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "logging.h"
|
||||
|
||||
|
||||
int us_memsink_fd_wait_frame(int fd, us_memsink_shared_s* mem, u64 last_id) {
|
||||
int us_memsink_fd_wait_frame(int fd, us_memsink_shared_s *mem, u64 last_id) {
|
||||
const ldf deadline_ts = us_get_now_monotonic() + 1; // wait_timeout
|
||||
ldf now_ts;
|
||||
do {
|
||||
@@ -57,9 +57,8 @@ int us_memsink_fd_wait_frame(int fd, us_memsink_shared_s* mem, u64 last_id) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
us_frame_s *us_memsink_fd_get_frame(int fd, us_memsink_shared_s *mem, u64 *frame_id, bool key_required) {
|
||||
us_frame_s *frame = us_frame_init();
|
||||
us_frame_set_data(frame, mem->data, mem->used);
|
||||
int us_memsink_fd_get_frame(int fd, us_memsink_shared_s *mem, us_frame_s *frame, u64 *frame_id, bool key_required) {
|
||||
us_frame_set_data(frame, us_memsink_get_data(mem), mem->used);
|
||||
US_FRAME_COPY_META(mem, frame);
|
||||
*frame_id = mem->id;
|
||||
mem->last_client_ts = us_get_now_monotonic();
|
||||
@@ -67,17 +66,14 @@ us_frame_s *us_memsink_fd_get_frame(int fd, us_memsink_shared_s *mem, u64 *frame
|
||||
mem->key_requested = true;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
bool retval = 0;
|
||||
if (frame->format != V4L2_PIX_FMT_H264) {
|
||||
US_JLOG_ERROR("video", "Got non-H264 frame from memsink");
|
||||
ok = false;
|
||||
retval = -1;
|
||||
}
|
||||
if (flock(fd, LOCK_UN) < 0) {
|
||||
US_JLOG_PERROR("video", "Can't unlock memsink");
|
||||
ok = false;
|
||||
retval = -1;
|
||||
}
|
||||
if (!ok) {
|
||||
US_DELETE(frame, us_frame_destroy);
|
||||
}
|
||||
return frame;
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -27,5 +27,5 @@
|
||||
#include "uslibs/memsinksh.h"
|
||||
|
||||
|
||||
int us_memsink_fd_wait_frame(int fd, us_memsink_shared_s* mem, u64 last_id);
|
||||
us_frame_s *us_memsink_fd_get_frame(int fd, us_memsink_shared_s *mem, u64 *frame_id, bool key_required);
|
||||
int us_memsink_fd_wait_frame(int fd, us_memsink_shared_s *mem, u64 last_id);
|
||||
int us_memsink_fd_get_frame(int fd, us_memsink_shared_s *mem, us_frame_s *frame, u64 *frame_id, bool key_required);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -40,14 +40,14 @@
|
||||
#include "uslibs/tools.h"
|
||||
#include "uslibs/threading.h"
|
||||
#include "uslibs/list.h"
|
||||
#include "uslibs/ring.h"
|
||||
#include "uslibs/memsinksh.h"
|
||||
#include "uslibs/tc358743.h"
|
||||
|
||||
#include "const.h"
|
||||
#include "logging.h"
|
||||
#include "queue.h"
|
||||
#include "client.h"
|
||||
#include "audio.h"
|
||||
#include "tc358743.h"
|
||||
#include "rtp.h"
|
||||
#include "rtpv.h"
|
||||
#include "rtpa.h"
|
||||
@@ -60,7 +60,7 @@ static const useconds_t _g_watchers_polling = 100000;
|
||||
|
||||
static us_janus_client_s *_g_clients = NULL;
|
||||
static janus_callbacks *_g_gw = NULL;
|
||||
static us_queue_s *_g_video_queue = NULL;
|
||||
static us_ring_s *_g_video_ring = NULL;
|
||||
static us_rtpv_s *_g_rtpv = NULL;
|
||||
static us_rtpa_s *_g_rtpa = NULL;
|
||||
|
||||
@@ -100,18 +100,18 @@ janus_plugin *create(void);
|
||||
|
||||
static void *_video_rtp_thread(void *arg) {
|
||||
(void)arg;
|
||||
|
||||
US_THREAD_RENAME("us_video_rtp");
|
||||
US_THREAD_SETTLE("us_video_rtp");
|
||||
atomic_store(&_g_video_rtp_tid_created, true);
|
||||
|
||||
while (!_STOP) {
|
||||
us_frame_s *frame;
|
||||
if (us_queue_get(_g_video_queue, (void **)&frame, 0.1) == 0) {
|
||||
const int ri = us_ring_consumer_acquire(_g_video_ring, 0.1);
|
||||
if (ri >= 0) {
|
||||
const us_frame_s *const frame = _g_video_ring->items[ri];
|
||||
_LOCK_VIDEO;
|
||||
const bool zero_playout_delay = (frame->gop == 0);
|
||||
us_rtpv_wrap(_g_rtpv, frame, zero_playout_delay);
|
||||
_UNLOCK_VIDEO;
|
||||
us_frame_destroy(frame);
|
||||
us_ring_consumer_release(_g_video_ring, ri);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@@ -119,10 +119,10 @@ static void *_video_rtp_thread(void *arg) {
|
||||
|
||||
static void *_video_sink_thread(void *arg) {
|
||||
(void)arg;
|
||||
|
||||
US_THREAD_RENAME("us_video_sink");
|
||||
US_THREAD_SETTLE("us_video_sink");
|
||||
atomic_store(&_g_video_sink_tid_created, true);
|
||||
|
||||
us_frame_s *drop = us_frame_init();
|
||||
u64 frame_id = 0;
|
||||
int once = 0;
|
||||
|
||||
@@ -136,12 +136,18 @@ static void *_video_sink_thread(void *arg) {
|
||||
int fd = -1;
|
||||
us_memsink_shared_s *mem = NULL;
|
||||
|
||||
const uz data_size = us_memsink_calculate_size(_g_config->video_sink_name);
|
||||
if (data_size == 0) {
|
||||
US_ONCE({ US_JLOG_ERROR("video", "Invalid memsink object suffix"); });
|
||||
goto close_memsink;
|
||||
}
|
||||
|
||||
if ((fd = shm_open(_g_config->video_sink_name, O_RDWR, 0)) <= 0) {
|
||||
US_ONCE({ US_JLOG_PERROR("video", "Can't open memsink"); });
|
||||
goto close_memsink;
|
||||
}
|
||||
|
||||
if ((mem = us_memsink_shared_map(fd)) == NULL) {
|
||||
if ((mem = us_memsink_shared_map(fd, data_size)) == NULL) {
|
||||
US_ONCE({ US_JLOG_PERROR("video", "Can't map memsink"); });
|
||||
goto close_memsink;
|
||||
}
|
||||
@@ -150,38 +156,68 @@ static void *_video_sink_thread(void *arg) {
|
||||
|
||||
US_JLOG_INFO("video", "Memsink opened; reading frames ...");
|
||||
while (!_STOP && _HAS_WATCHERS) {
|
||||
const int result = us_memsink_fd_wait_frame(fd, mem, frame_id);
|
||||
if (result == 0) {
|
||||
us_frame_s *const frame = us_memsink_fd_get_frame(fd, mem, &frame_id, atomic_load(&_g_key_required));
|
||||
if (frame == NULL) {
|
||||
const int waited = us_memsink_fd_wait_frame(fd, mem, frame_id);
|
||||
if (waited == 0) {
|
||||
const int ri = us_ring_producer_acquire(_g_video_ring, 0);
|
||||
us_frame_s *frame;
|
||||
if (ri >= 0) {
|
||||
frame = _g_video_ring->items[ri];
|
||||
} else {
|
||||
US_ONCE({ US_JLOG_PERROR("video", "Video ring is full"); });
|
||||
frame = drop;
|
||||
}
|
||||
|
||||
const int got = us_memsink_fd_get_frame(fd, mem, frame, &frame_id, atomic_load(&_g_key_required));
|
||||
if (ri >= 0) {
|
||||
us_ring_producer_release(_g_video_ring, ri);
|
||||
}
|
||||
if (got < 0) {
|
||||
goto close_memsink;
|
||||
}
|
||||
if (frame->key) {
|
||||
|
||||
if (ri >= 0 && frame->key) {
|
||||
atomic_store(&_g_key_required, false);
|
||||
}
|
||||
if (us_queue_put(_g_video_queue, frame, 0) != 0) {
|
||||
US_ONCE({ US_JLOG_PERROR("video", "Video queue is full"); });
|
||||
us_frame_destroy(frame);
|
||||
}
|
||||
} else if (result == -1) {
|
||||
} else if (waited != -2) {
|
||||
goto close_memsink;
|
||||
}
|
||||
}
|
||||
|
||||
close_memsink:
|
||||
US_DELETE(mem, us_memsink_shared_unmap);
|
||||
US_CLOSE_FD(fd, close);
|
||||
if (mem != NULL) {
|
||||
us_memsink_shared_unmap(mem, data_size);
|
||||
mem = NULL;
|
||||
}
|
||||
US_CLOSE_FD(fd);
|
||||
US_JLOG_INFO("video", "Memsink closed");
|
||||
sleep(1); // error_delay
|
||||
}
|
||||
|
||||
us_frame_destroy(drop);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _check_tc358743_audio(uint *audio_hz) {
|
||||
int fd;
|
||||
if ((fd = open(_g_config->tc358743_dev_path, O_RDWR)) < 0) {
|
||||
US_JLOG_PERROR("audio", "Can't open TC358743 V4L2 device");
|
||||
return -1;
|
||||
}
|
||||
const int checked = us_tc358743_xioctl_get_audio_hz(fd, audio_hz);
|
||||
if (checked < 0) {
|
||||
US_JLOG_PERROR("audio", "Can't check TC358743 audio state (%d)", checked);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *_audio_thread(void *arg) {
|
||||
(void)arg;
|
||||
|
||||
US_THREAD_RENAME("us_audio");
|
||||
US_THREAD_SETTLE("us_audio");
|
||||
atomic_store(&_g_audio_tid_created, true);
|
||||
|
||||
assert(_g_config->audio_dev_name != NULL);
|
||||
assert(_g_config->tc358743_dev_path != NULL);
|
||||
|
||||
@@ -193,32 +229,27 @@ static void *_audio_thread(void *arg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
us_tc358743_info_s info = {0};
|
||||
uint audio_hz = 0;
|
||||
us_audio_s *audio = NULL;
|
||||
|
||||
if (us_tc358743_read_info(_g_config->tc358743_dev_path, &info) < 0) {
|
||||
if (_check_tc358743_audio(&audio_hz) < 0) {
|
||||
goto close_audio;
|
||||
}
|
||||
if (!info.has_audio) {
|
||||
if (audio_hz == 0) {
|
||||
US_ONCE({ US_JLOG_INFO("audio", "No audio presented from the host"); });
|
||||
goto close_audio;
|
||||
}
|
||||
US_ONCE({ US_JLOG_INFO("audio", "Detected host audio"); });
|
||||
if ((audio = us_audio_init(_g_config->audio_dev_name, info.audio_hz)) == NULL) {
|
||||
if ((audio = us_audio_init(_g_config->audio_dev_name, audio_hz)) == NULL) {
|
||||
goto close_audio;
|
||||
}
|
||||
|
||||
once = 0;
|
||||
|
||||
while (!_STOP && _HAS_WATCHERS && _HAS_LISTENERS) {
|
||||
if (
|
||||
us_tc358743_read_info(_g_config->tc358743_dev_path, &info) < 0
|
||||
|| !info.has_audio
|
||||
|| audio->pcm_hz != info.audio_hz
|
||||
) {
|
||||
if (_check_tc358743_audio(&audio_hz) < 0 || audio->pcm_hz != audio_hz) {
|
||||
goto close_audio;
|
||||
}
|
||||
|
||||
uz size = US_RTP_DATAGRAM_SIZE - US_RTP_HEADER_SIZE;
|
||||
u8 data[size];
|
||||
u64 pts;
|
||||
@@ -258,7 +289,7 @@ static int _plugin_init(janus_callbacks *gw, const char *config_dir_path) {
|
||||
}
|
||||
_g_gw = gw;
|
||||
|
||||
_g_video_queue = us_queue_init(1024);
|
||||
US_RING_INIT_WITH_ITEMS(_g_video_ring, 64, us_frame_init);
|
||||
_g_rtpv = us_rtpv_init(_relay_rtp_clients);
|
||||
if (_g_config->audio_dev_name != NULL && us_audio_probe(_g_config->audio_dev_name)) {
|
||||
_g_rtpa = us_rtpa_init(_relay_rtp_clients);
|
||||
@@ -286,7 +317,7 @@ static void _plugin_destroy(void) {
|
||||
us_janus_client_destroy(client);
|
||||
});
|
||||
|
||||
US_QUEUE_DELETE_WITH_ITEMS(_g_video_queue, us_frame_destroy);
|
||||
US_RING_DELETE_WITH_ITEMS(_g_video_ring, us_frame_destroy);
|
||||
|
||||
US_DELETE(_g_rtpa, us_rtpa_destroy);
|
||||
US_DELETE(_g_rtpv, us_rtpv_destroy);
|
||||
@@ -431,12 +462,25 @@ static struct janus_plugin_result *_plugin_handle_message(
|
||||
|
||||
} else if (!strcmp(request_str, "watch")) {
|
||||
bool with_audio = false;
|
||||
uint video_orient = 0;
|
||||
{
|
||||
json_t *const params = json_object_get(msg, "params");
|
||||
if (params != NULL) {
|
||||
json_t *const audio = json_object_get(params, "audio");
|
||||
if (audio != NULL && json_is_boolean(audio)) {
|
||||
with_audio = (_g_rtpa != NULL && json_boolean_value(audio));
|
||||
{
|
||||
json_t *const obj = json_object_get(params, "audio");
|
||||
if (obj != NULL && json_is_boolean(obj)) {
|
||||
with_audio = (_g_rtpa != NULL && json_boolean_value(obj));
|
||||
}
|
||||
}
|
||||
{
|
||||
json_t *const obj = json_object_get(params, "orientation");
|
||||
if (obj != NULL && json_is_integer(obj)) {
|
||||
video_orient = json_integer_value(obj);
|
||||
switch (video_orient) {
|
||||
case 90: case 180: case 270: break;
|
||||
default: video_orient = 0; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -476,6 +520,7 @@ static struct janus_plugin_result *_plugin_handle_message(
|
||||
US_LIST_ITERATE(_g_clients, client, {
|
||||
if (client->session == session) {
|
||||
atomic_store(&client->transmit_audio, with_audio);
|
||||
atomic_store(&client->video_orient, video_orient);
|
||||
}
|
||||
has_listeners = (has_listeners || atomic_load(&client->transmit_audio));
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# This source file is partially based on this code: #
|
||||
# - https://github.com/catid/kvm/blob/master/kvm_pipeline/src #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -31,26 +31,22 @@
|
||||
#include "uslibs/tools.h"
|
||||
|
||||
|
||||
us_rtp_s *us_rtp_init(uint payload, bool video) {
|
||||
us_rtp_s *us_rtp_init(void) {
|
||||
us_rtp_s *rtp;
|
||||
US_CALLOC(rtp, 1);
|
||||
rtp->payload = payload;
|
||||
rtp->video = video;
|
||||
rtp->ssrc = us_triple_u32(us_get_now_monotonic_u64());
|
||||
return rtp;
|
||||
}
|
||||
|
||||
us_rtp_s *us_rtp_dup(const us_rtp_s *rtp) {
|
||||
us_rtp_s *new;
|
||||
US_CALLOC(new, 1);
|
||||
memcpy(new, rtp, sizeof(us_rtp_s));
|
||||
return new;
|
||||
}
|
||||
|
||||
void us_rtp_destroy(us_rtp_s *rtp) {
|
||||
free(rtp);
|
||||
}
|
||||
|
||||
void us_rtp_assign(us_rtp_s *rtp, uint payload, bool video) {
|
||||
rtp->payload = payload;
|
||||
rtp->video = video;
|
||||
rtp->ssrc = us_triple_u32(us_get_now_monotonic_u64());
|
||||
}
|
||||
|
||||
void us_rtp_write_header(us_rtp_s *rtp, u32 pts, bool marked) {
|
||||
u32 word0 = 0x80000000;
|
||||
if (marked) {
|
||||
@@ -61,7 +57,7 @@ void us_rtp_write_header(us_rtp_s *rtp, u32 pts, bool marked) {
|
||||
++rtp->seq;
|
||||
|
||||
# define WRITE_BE_U32(x_offset, x_value) \
|
||||
*((u32 *)(rtp->datagram + x_offset)) = __builtin_bswap32(x_value)
|
||||
*((u32*)(rtp->datagram + x_offset)) = __builtin_bswap32(x_value)
|
||||
WRITE_BE_U32(0, word0);
|
||||
WRITE_BE_U32(4, pts);
|
||||
WRITE_BE_U32(8, rtp->ssrc);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -44,8 +44,8 @@ typedef struct {
|
||||
typedef void (*us_rtp_callback_f)(const us_rtp_s *rtp);
|
||||
|
||||
|
||||
us_rtp_s *us_rtp_init(uint payload, bool video);
|
||||
us_rtp_s *us_rtp_dup(const us_rtp_s *rtp);
|
||||
us_rtp_s *us_rtp_init(void);
|
||||
void us_rtp_destroy(us_rtp_s *rtp);
|
||||
|
||||
void us_rtp_assign(us_rtp_s *rtp, uint payload, bool video);
|
||||
void us_rtp_write_header(us_rtp_s *rtp, u32 pts, bool marked);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -32,7 +32,8 @@
|
||||
us_rtpa_s *us_rtpa_init(us_rtp_callback_f callback) {
|
||||
us_rtpa_s *rtpa;
|
||||
US_CALLOC(rtpa, 1);
|
||||
rtpa->rtp = us_rtp_init(111, false);
|
||||
rtpa->rtp = us_rtp_init();
|
||||
us_rtp_assign(rtpa->rtp, 111, false);
|
||||
rtpa->callback = callback;
|
||||
return rtpa;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# This source file is partially based on this code: #
|
||||
# - https://github.com/catid/kvm/blob/master/kvm_pipeline/src #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -44,7 +44,8 @@ static sz _find_annexb(const u8 *data, uz size);
|
||||
us_rtpv_s *us_rtpv_init(us_rtp_callback_f callback) {
|
||||
us_rtpv_s *rtpv;
|
||||
US_CALLOC(rtpv, 1);
|
||||
rtpv->rtp = us_rtp_init(96, true);
|
||||
rtpv->rtp = us_rtp_init();
|
||||
us_rtp_assign(rtpv->rtp, 96, true);
|
||||
rtpv->callback = callback;
|
||||
return rtpv;
|
||||
}
|
||||
@@ -70,6 +71,7 @@ char *us_rtpv_make_sdp(us_rtpv_s *rtpv) {
|
||||
"a=rtcp-fb:%u goog-remb" RN
|
||||
"a=ssrc:%" PRIu32 " cname:ustreamer" RN
|
||||
"a=extmap:1 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay" RN
|
||||
"a=extmap:2 urn:3gpp:video-orientation" RN
|
||||
"a=sendonly" RN,
|
||||
pl, pl, pl, pl,
|
||||
pl, pl, pl,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
1
janus/src/uslibs/memsinksh.c
Symbolic link
1
janus/src/uslibs/memsinksh.c
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../src/libs/memsinksh.c
|
||||
1
janus/src/uslibs/queue.c
Symbolic link
1
janus/src/uslibs/queue.c
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../src/libs/queue.c
|
||||
1
janus/src/uslibs/queue.h
Symbolic link
1
janus/src/uslibs/queue.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../src/libs/queue.h
|
||||
1
janus/src/uslibs/ring.c
Symbolic link
1
janus/src/uslibs/ring.c
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../src/libs/ring.c
|
||||
1
janus/src/uslibs/ring.h
Symbolic link
1
janus/src/uslibs/ring.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../src/libs/ring.h
|
||||
1
janus/src/uslibs/tc358743.c
Symbolic link
1
janus/src/uslibs/tc358743.c
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../src/libs/tc358743.c
|
||||
1
janus/src/uslibs/tc358743.h
Symbolic link
1
janus/src/uslibs/tc358743.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../src/libs/tc358743.h
|
||||
@@ -1,44 +0,0 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
typedef long long sll;
|
||||
typedef ssize_t sz;
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
|
||||
typedef unsigned uint;
|
||||
typedef unsigned long long ull;
|
||||
typedef size_t uz;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
typedef long double ldf;
|
||||
1
janus/src/uslibs/types.h
Symbolic link
1
janus/src/uslibs/types.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../src/libs/types.h
|
||||
@@ -33,7 +33,7 @@ max-line-length = 160
|
||||
|
||||
[BASIC]
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names = _, __, x, y, ws, make-html-h, make-jpeg-h, make-ico-h
|
||||
good-names = _, __, x, y, ws, make-html-h, make-ico-h
|
||||
|
||||
# Regular expression matching correct method names
|
||||
method-rgx = [a-z_][a-z0-9_]{2,50}$
|
||||
|
||||
@@ -13,7 +13,7 @@ commands = cppcheck \
|
||||
--std=c17 \
|
||||
--error-exitcode=1 \
|
||||
--quiet \
|
||||
--enable=warning,unusedFunction,portability,performance,style \
|
||||
--enable=warning,portability,performance,style \
|
||||
--suppress=assignmentInAssert \
|
||||
--suppress=variableScope \
|
||||
--inline-suppr \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" Manpage for ustreamer-dump.
|
||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||
.TH USTREAMER-DUMP 1 "version 5.53" "January 2021"
|
||||
.TH USTREAMER-DUMP 1 "version 6.6" "January 2021"
|
||||
|
||||
.SH NAME
|
||||
ustreamer-dump \- Dump uStreamer's memory sink to file
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" Manpage for ustreamer.
|
||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||
.TH USTREAMER 1 "version 5.53" "November 2020"
|
||||
.TH USTREAMER 1 "version 6.6" "November 2020"
|
||||
|
||||
.SH NAME
|
||||
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
||||
@@ -17,7 +17,7 @@ Without arguments, \fBustreamer\fR will try to open \fB/dev/video0\fR with 640x4
|
||||
|
||||
Please note that since µStreamer v2\.0 cross\-domain requests were disabled by default for security reasons\. To enable the old behavior, use the option \fB\-\-allow\-origin=\e*\fR\.
|
||||
|
||||
For example, the recommended way of running µStreamer with Auvidea B101 on a Raspberry Pi is:
|
||||
For example, the recommended way of running µStreamer with TC358743-based capture device on a Raspberry Pi is:
|
||||
|
||||
\fBustreamer \e\fR
|
||||
.RS
|
||||
@@ -27,7 +27,7 @@ For example, the recommended way of running µStreamer with Auvidea B101 on a Ra
|
||||
.nf
|
||||
\fB\-\-workers=3 \e\fR # Maximum workers for V4L2 encoder
|
||||
.nf
|
||||
\fB\-\-persistent \e\fR # Don\'t re\-initialize device on timeout (for example when HDMI cable was disconnected)
|
||||
\fB\-\-persistent \e\fR # Suppress repetitive signal source errors (for example when HDMI cable was disconnected)
|
||||
.nf
|
||||
\fB\-\-dv\-timings \e\fR # Use DV\-timings
|
||||
.nf
|
||||
@@ -69,7 +69,7 @@ Desired FPS. Default: maximum possible.
|
||||
Drop frames smaller then this limit. Useful if the device produces small\-sized garbage frames. Default: 128 bytes.
|
||||
.TP
|
||||
.BR \-n ", " \-\-persistent
|
||||
Don't re\-initialize device on timeout. Default: disabled.
|
||||
Suppress repetitive signal source errors. Default: disabled.
|
||||
.TP
|
||||
.BR \-t ", " \-\-dv\-timings
|
||||
Enable DV-timings querying and events processing to automatic resolution change. Default: disabled.
|
||||
@@ -103,10 +103,10 @@ NOOP ─ Don't compress MJPEG stream (do nothing).
|
||||
It doesn't do anything. Still here for compatibility.
|
||||
.TP
|
||||
.BR \-k\ \fIpath ", " \-\-blank\ \fIpath
|
||||
Path to JPEG file that will be shown when the device is disconnected during the streaming. Default: black screen 640x480 with 'NO SIGNAL'.
|
||||
It doesn't do anything. Still here for compatibility.
|
||||
.TP
|
||||
.BR \-K\ \fIsec ", " \-\-last\-as\-blank\ \fIsec
|
||||
Show the last frame received from the camera after it was disconnected, but no more than specified time (or endlessly if 0 is specified). If the device has not yet been online, display 'NO SIGNAL' or the image specified by option \-\-blank. Note: currently this option has no effect on memory sinks. Default: disabled.
|
||||
It doesn't do anything. Still here for compatibility.
|
||||
.TP
|
||||
.BR \-l ", " \-\-slowdown
|
||||
Slowdown capturing to 1 FPS or less when no stream or sink clients are connected. Useful to reduce CPU consumption. Default: disabled.
|
||||
@@ -212,25 +212,25 @@ Timeout for client connections. Default: 10.
|
||||
.SS "JPEG sink options"
|
||||
With shared memory sink you can write a stream to a file. See \fBustreamer-dump\fR(1) for more info.
|
||||
.TP
|
||||
.BR \-\-sink\ \fIname
|
||||
Use the specified shared memory object to sink JPEG frames. Default: disabled.
|
||||
.BR \-\-jpeg\-sink\ \fIname
|
||||
Use the specified shared memory object to sink JPEG frames. The name should end with a suffix ".jpeg" or ":jpeg". Default: disabled.
|
||||
.TP
|
||||
.BR \-\-sink\-mode\ \fImode
|
||||
.BR \-\-jpeg\-sink\-mode\ \fImode
|
||||
Set JPEG sink permissions (like 777). Default: 660.
|
||||
.TP
|
||||
.BR \-\-sink\-rm
|
||||
.BR \-\-jpeg\-sink\-rm
|
||||
Remove shared memory on stop. Default: disabled.
|
||||
.TP
|
||||
.BR \-\-sink\-client\-ttl\ \fIsec
|
||||
.BR \-\-jpeg\-sink\-client\-ttl\ \fIsec
|
||||
Client TTL. Default: 10.
|
||||
.TP
|
||||
.BR \-\-sink\-timeout\ \fIsec
|
||||
.BR \-\-jpeg\-sink\-timeout\ \fIsec
|
||||
Timeout for lock. Default: 1.
|
||||
|
||||
.SS "H264 sink options"
|
||||
.TP
|
||||
.BR \-\-h264\-sink\ \fIname
|
||||
Use the specified shared memory object to sink H264 frames. Default: disabled.
|
||||
Use the specified shared memory object to sink H264 frames. The name should end with a suffix ".h264" or ":h264". Default: disabled.
|
||||
.TP
|
||||
.BR \-\-h264\-sink\-mode\ \fImode
|
||||
Set H264 sink permissions (like 777). Default: 660.
|
||||
@@ -253,6 +253,22 @@ Interval between keyframes. Default: 30.
|
||||
.BR \-\-h264\-m2m\-device\ \fI/dev/path
|
||||
Path to V4L2 mem-to-mem encoder device. Default: auto-select.
|
||||
|
||||
.SS "RAW sink options"
|
||||
.TP
|
||||
.BR \-\-raw\-sink\ \fIname
|
||||
Use the specified shared memory object to sink RAW frames. The name should end with a suffix ".raw" or ":raw". Default: disabled.
|
||||
.TP
|
||||
.BR \-\-raw\-sink\-mode\ \fImode
|
||||
Set RAW sink permissions (like 777). Default: 660.
|
||||
.TP
|
||||
.BR \-\-raw\-sink\-rm
|
||||
Remove shared memory on stop. Default: disabled.
|
||||
.TP
|
||||
.BR \-\-raw\-sink\-client\-ttl\ \fIsec
|
||||
Client TTL. Default: 10.
|
||||
.TP
|
||||
.BR \-\-raw\-sink\-timeout\ \fIsec
|
||||
Timeout for lock. Default: 1.
|
||||
|
||||
.SS "Process options"
|
||||
.TP
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
|
||||
pkgname=ustreamer
|
||||
pkgver=5.53
|
||||
pkgver=6.6
|
||||
pkgrel=1
|
||||
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
||||
url="https://github.com/pikvm/ustreamer"
|
||||
@@ -19,7 +19,7 @@ _options="WITH_GPIO=1 WITH_SYSTEMD=1"
|
||||
if [ -e /usr/bin/python3 ]; then
|
||||
_options="$_options WITH_PYTHON=1"
|
||||
depends+=(python)
|
||||
makedepends+=(python-setuptools)
|
||||
makedepends+=(python-setuptools python-pip python-build)
|
||||
fi
|
||||
if [ -e /usr/include/janus/plugins/plugin.h ];then
|
||||
depends+=(janus-gateway alsa-lib opus)
|
||||
@@ -28,12 +28,6 @@ if [ -e /usr/include/janus/plugins/plugin.h ];then
|
||||
fi
|
||||
|
||||
|
||||
# LD does not link mmal with this option
|
||||
# This DOESN'T affect setup.py
|
||||
LDFLAGS="${LDFLAGS//--as-needed/}"
|
||||
export LDFLAGS="${LDFLAGS//,,/,}"
|
||||
|
||||
|
||||
build() {
|
||||
cd "$srcdir"
|
||||
rm -rf $pkgname-build
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=ustreamer
|
||||
PKG_VERSION:=5.53
|
||||
PKG_VERSION:=6.6
|
||||
PKG_RELEASE:=1
|
||||
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
||||
|
||||
|
||||
2
python/MANIFEST.in
Normal file
2
python/MANIFEST.in
Normal file
@@ -0,0 +1,2 @@
|
||||
include setup.py
|
||||
recursive-include src *.c *h
|
||||
@@ -1,6 +1,6 @@
|
||||
-include ../config.mk
|
||||
|
||||
DESTDIR ?=
|
||||
R_DESTDIR ?=
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
PY ?= python3
|
||||
@@ -9,12 +9,14 @@ PY ?= python3
|
||||
# =====
|
||||
all:
|
||||
$(info == PY_BUILD ustreamer-*.so)
|
||||
$(ECHO) $(PY) setup.py build
|
||||
rm -rf root
|
||||
$(ECHO) $(PY) -m build --skip-dependency-check --no-isolation
|
||||
$(ECHO) $(PY) -m pip install dist/*.whl --ignore-installed --root=./root
|
||||
|
||||
|
||||
install:
|
||||
$(PY) setup.py install --prefix=$(PREFIX) --root=$(if $(DESTDIR),$(DESTDIR),/)
|
||||
$(PY) -m pip install dist/*.whl --ignore-installed --prefix=$(PREFIX) --root=$(if $(R_DESTDIR),$(R_DESTDIR),/)
|
||||
|
||||
|
||||
clean:
|
||||
rm -rf build ustreamer.egg-info
|
||||
rm -rf root dist ustreamer.egg-info
|
||||
|
||||
@@ -17,7 +17,7 @@ def _find_sources(suffix: str) -> list[str]:
|
||||
if __name__ == "__main__":
|
||||
setup(
|
||||
name="ustreamer",
|
||||
version="5.53",
|
||||
version="6.6",
|
||||
description="uStreamer tools",
|
||||
author="Maxim Devaev",
|
||||
author_email="mdevaev@gmail.com",
|
||||
@@ -29,7 +29,6 @@ if __name__ == "__main__":
|
||||
extra_compile_args=["-std=c17", "-D_GNU_SOURCE"],
|
||||
undef_macros=["NDEBUG"],
|
||||
sources=_find_sources(".c"),
|
||||
depends=_find_sources(".h"),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
1
python/src/uslibs/memsinksh.c
Symbolic link
1
python/src/uslibs/memsinksh.c
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../src/libs/memsinksh.c
|
||||
@@ -1,44 +0,0 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
typedef long long sll;
|
||||
typedef ssize_t sz;
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
|
||||
typedef unsigned uint;
|
||||
typedef unsigned long long ull;
|
||||
typedef size_t uz;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
typedef long double ldf;
|
||||
1
python/src/uslibs/types.h
Symbolic link
1
python/src/uslibs/types.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../src/libs/types.h
|
||||
@@ -26,6 +26,7 @@ typedef struct {
|
||||
double lock_timeout;
|
||||
double wait_timeout;
|
||||
double drop_same_frames;
|
||||
uz data_size;
|
||||
|
||||
int fd;
|
||||
us_memsink_shared_s *mem;
|
||||
@@ -37,8 +38,11 @@ typedef struct {
|
||||
|
||||
|
||||
static void _MemsinkObject_destroy_internals(_MemsinkObject *self) {
|
||||
US_DELETE(self->mem, us_memsink_shared_unmap);
|
||||
US_CLOSE_FD(self->fd, close);
|
||||
if (self->mem != NULL) {
|
||||
us_memsink_shared_unmap(self->mem, self->data_size);
|
||||
self->mem = NULL;
|
||||
}
|
||||
US_CLOSE_FD(self->fd);
|
||||
US_DELETE(self->frame, us_frame_destroy);
|
||||
}
|
||||
|
||||
@@ -64,13 +68,18 @@ static int _MemsinkObject_init(_MemsinkObject *self, PyObject *args, PyObject *k
|
||||
SET_DOUBLE(drop_same_frames, >= 0);
|
||||
# undef SET_DOUBLE
|
||||
|
||||
if ((self->data_size = us_memsink_calculate_size(self->obj)) == 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid memsink object suffix");
|
||||
return -1;
|
||||
}
|
||||
|
||||
self->frame = us_frame_init();
|
||||
|
||||
if ((self->fd = shm_open(self->obj, O_RDWR, 0)) == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
if ((self->mem = us_memsink_shared_map(self->fd)) == NULL) {
|
||||
if ((self->mem = us_memsink_shared_map(self->fd, self->data_size)) == NULL) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
@@ -99,67 +108,76 @@ static PyObject *_MemsinkObject_close(_MemsinkObject *self, PyObject *Py_UNUSED(
|
||||
|
||||
static PyObject *_MemsinkObject_enter(_MemsinkObject *self, PyObject *Py_UNUSED(ignored)) {
|
||||
Py_INCREF(self);
|
||||
return (PyObject *)self;
|
||||
return (PyObject*)self;
|
||||
}
|
||||
|
||||
static PyObject *_MemsinkObject_exit(_MemsinkObject *self, PyObject *Py_UNUSED(ignored)) {
|
||||
return PyObject_CallMethod((PyObject *)self, "close", "");
|
||||
return PyObject_CallMethod((PyObject*)self, "close", "");
|
||||
}
|
||||
|
||||
static int _wait_frame(_MemsinkObject *self) {
|
||||
const ldf deadline_ts = us_get_now_monotonic() + self->wait_timeout;
|
||||
|
||||
# define RETURN_OS_ERROR { \
|
||||
Py_BLOCK_THREADS \
|
||||
PyErr_SetFromErrno(PyExc_OSError); \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
int locked = -1;
|
||||
ldf now_ts;
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
|
||||
const int retval = us_flock_timedwait_monotonic(self->fd, self->lock_timeout);
|
||||
locked = us_flock_timedwait_monotonic(self->fd, self->lock_timeout);
|
||||
now_ts = us_get_now_monotonic();
|
||||
|
||||
if (retval < 0 && errno != EWOULDBLOCK) {
|
||||
RETURN_OS_ERROR;
|
||||
|
||||
} else if (retval == 0) {
|
||||
us_memsink_shared_s *mem = self->mem;
|
||||
if (mem->magic == US_MEMSINK_MAGIC && mem->version == US_MEMSINK_VERSION && mem->id != self->frame_id) {
|
||||
if (self->drop_same_frames > 0) {
|
||||
if (
|
||||
US_FRAME_COMPARE_META_USED_NOTS(self->mem, self->frame)
|
||||
&& (self->frame_ts + self->drop_same_frames > now_ts)
|
||||
&& !memcmp(self->frame->data, mem->data, mem->used)
|
||||
) {
|
||||
self->frame_id = mem->id;
|
||||
goto drop;
|
||||
}
|
||||
}
|
||||
|
||||
Py_BLOCK_THREADS
|
||||
return 0;
|
||||
if (locked < 0) {
|
||||
if (errno == EWOULDBLOCK) {
|
||||
goto retry;
|
||||
}
|
||||
goto os_error;
|
||||
}
|
||||
|
||||
if (flock(self->fd, LOCK_UN) < 0) {
|
||||
RETURN_OS_ERROR;
|
||||
us_memsink_shared_s *mem = self->mem;
|
||||
if (mem->magic != US_MEMSINK_MAGIC || mem->version != US_MEMSINK_VERSION) {
|
||||
goto retry;
|
||||
}
|
||||
|
||||
// Let the sink know that the client is alive
|
||||
mem->last_client_ts = now_ts;
|
||||
|
||||
if (mem->id == self->frame_id) {
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (self->drop_same_frames > 0) {
|
||||
if (
|
||||
US_FRAME_COMPARE_GEOMETRY(self->mem, self->frame)
|
||||
&& (self->frame_ts + self->drop_same_frames > now_ts)
|
||||
&& !memcmp(self->frame->data, us_memsink_get_data(mem), mem->used)
|
||||
) {
|
||||
self->frame_id = mem->id;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
drop:
|
||||
// New frame found
|
||||
Py_BLOCK_THREADS
|
||||
return 0;
|
||||
|
||||
os_error:
|
||||
Py_BLOCK_THREADS
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return -1;
|
||||
|
||||
retry:
|
||||
if (locked >= 0 && flock(self->fd, LOCK_UN) < 0) {
|
||||
goto os_error;
|
||||
}
|
||||
if (usleep(1000) < 0) {
|
||||
RETURN_OS_ERROR;
|
||||
goto os_error;
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
if (PyErr_CheckSignals() < 0) {
|
||||
return -1;
|
||||
}
|
||||
} while (now_ts < deadline_ts);
|
||||
|
||||
} while (now_ts < deadline_ts);
|
||||
return -2;
|
||||
# undef RETURN_OS_ERROR
|
||||
}
|
||||
|
||||
static PyObject *_MemsinkObject_wait_frame(_MemsinkObject *self, PyObject *args, PyObject *kwargs) {
|
||||
@@ -181,11 +199,10 @@ static PyObject *_MemsinkObject_wait_frame(_MemsinkObject *self, PyObject *args,
|
||||
}
|
||||
|
||||
us_memsink_shared_s *mem = self->mem;
|
||||
us_frame_set_data(self->frame, mem->data, mem->used);
|
||||
us_frame_set_data(self->frame, us_memsink_get_data(mem), mem->used);
|
||||
US_FRAME_COPY_META(self->mem, self->frame);
|
||||
self->frame_id = mem->id;
|
||||
self->frame_ts = us_get_now_monotonic();
|
||||
mem->last_client_ts = self->frame_ts;
|
||||
if (key_required) {
|
||||
mem->key_requested = true;
|
||||
}
|
||||
@@ -222,7 +239,7 @@ static PyObject *_MemsinkObject_wait_frame(_MemsinkObject *self, PyObject *args,
|
||||
SET_NUMBER(grab_ts, Double, Float);
|
||||
SET_NUMBER(encode_begin_ts, Double, Float);
|
||||
SET_NUMBER(encode_end_ts, Double, Float);
|
||||
SET_VALUE("data", PyBytes_FromStringAndSize((const char *)self->frame->data, self->frame->used));
|
||||
SET_VALUE("data", PyBytes_FromStringAndSize((const char*)self->frame->data, self->frame->used));
|
||||
|
||||
# undef SET_NUMBER
|
||||
# undef SET_VALUE
|
||||
@@ -285,7 +302,7 @@ static PyModuleDef _Module = {
|
||||
.m_size = -1,
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC PyInit_ustreamer(void) { // cppcheck-suppress unusedFunction
|
||||
PyMODINIT_FUNC PyInit_ustreamer(void) {
|
||||
PyObject *module = PyModule_Create(&_Module);
|
||||
if (module == NULL) {
|
||||
return NULL;
|
||||
@@ -297,7 +314,7 @@ PyMODINIT_FUNC PyInit_ustreamer(void) { // cppcheck-suppress unusedFunction
|
||||
|
||||
Py_INCREF(&_MemsinkType);
|
||||
|
||||
if (PyModule_AddObject(module, "Memsink", (PyObject *)&_MemsinkType) < 0) {
|
||||
if (PyModule_AddObject(module, "Memsink", (PyObject*)&_MemsinkType) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
15
src/Makefile
15
src/Makefile
@@ -1,4 +1,4 @@
|
||||
DESTDIR ?=
|
||||
R_DESTDIR ?=
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
CC ?= gcc
|
||||
@@ -14,7 +14,7 @@ _V4P = ustreamer-v4p.bin
|
||||
_CFLAGS = -MD -c -std=c17 -Wall -Wextra -D_GNU_SOURCE $(CFLAGS)
|
||||
_LDFLAGS = $(LDFLAGS)
|
||||
|
||||
_COMMON_LIBS = -lm -ljpeg -pthread -lrt
|
||||
_COMMON_LIBS = -lm -ljpeg -pthread -lrt -latomic
|
||||
|
||||
_USTR_LIBS = $(_COMMON_LIBS) -levent -levent_pthreads
|
||||
_USTR_SRCS = $(shell ls \
|
||||
@@ -88,17 +88,22 @@ override _CFLAGS += $(shell pkg-config --cflags libdrm)
|
||||
_V4P_LDFLAGS = $(shell pkg-config --libs libdrm)
|
||||
endif
|
||||
|
||||
|
||||
# =====
|
||||
all: $(_TARGETS)
|
||||
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||
for i in $(_TARGETS); do install -m755 $$i $(DESTDIR)$(PREFIX)/bin/$(subst .bin,,$$i); done
|
||||
mkdir -p $(R_DESTDIR)$(PREFIX)/bin
|
||||
for i in $(subst .bin,,$(_TARGETS)); do \
|
||||
install -m755 $$i.bin $(R_DESTDIR)$(PREFIX)/bin/$$i; \
|
||||
done
|
||||
|
||||
|
||||
install-strip: install
|
||||
for i in $(_TARGETS); do strip $(DESTDIR)$(PREFIX)/bin/$(subst .bin,,$$i); done
|
||||
for i in $(subst .bin,,$(_TARGETS)); do \
|
||||
strip $(R_DESTDIR)$(PREFIX)/bin/$$i; \
|
||||
done
|
||||
|
||||
|
||||
$(_USTR): $(_USTR_SRCS:%.c=$(_BUILD)/%.o)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -47,7 +47,7 @@ us_output_file_s *us_output_file_init(const char *path, bool json) {
|
||||
}
|
||||
|
||||
void us_output_file_write(void *v_output, const us_frame_s *frame) {
|
||||
us_output_file_s *output = (us_output_file_s *)v_output;
|
||||
us_output_file_s *output = v_output;
|
||||
if (output->json) {
|
||||
us_base64_encode(frame->data, frame->used, &output->base64_data, &output->base64_allocated);
|
||||
fprintf(output->fp,
|
||||
@@ -66,7 +66,7 @@ void us_output_file_write(void *v_output, const us_frame_s *frame) {
|
||||
}
|
||||
|
||||
void us_output_file_destroy(void *v_output) {
|
||||
us_output_file_s *output = (us_output_file_s *)v_output;
|
||||
us_output_file_s *output = v_output;
|
||||
US_DELETE(output->base64_data, free);
|
||||
if (output->fp && output->fp != stdout) {
|
||||
if (fclose(output->fp) < 0) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
#include <getopt.h>
|
||||
@@ -36,6 +35,7 @@
|
||||
#include "../libs/logging.h"
|
||||
#include "../libs/frame.h"
|
||||
#include "../libs/memsink.h"
|
||||
#include "../libs/signal.h"
|
||||
#include "../libs/options.h"
|
||||
|
||||
#include "file.h"
|
||||
@@ -95,7 +95,6 @@ typedef struct {
|
||||
|
||||
|
||||
static void _signal_handler(int signum);
|
||||
static void _install_signal_handlers(void);
|
||||
|
||||
static int _dump_sink(
|
||||
const char *sink_name, unsigned sink_timeout,
|
||||
@@ -183,14 +182,14 @@ int main(int argc, char *argv[]) {
|
||||
_output_context_s ctx = {0};
|
||||
|
||||
if (output_path && output_path[0] != '\0') {
|
||||
if ((ctx.v_output = (void *)us_output_file_init(output_path, output_json)) == NULL) {
|
||||
if ((ctx.v_output = (void*)us_output_file_init(output_path, output_json)) == NULL) {
|
||||
return 1;
|
||||
}
|
||||
ctx.write = us_output_file_write;
|
||||
ctx.destroy = us_output_file_destroy;
|
||||
}
|
||||
|
||||
_install_signal_handlers();
|
||||
us_install_signals_handler(_signal_handler, false);
|
||||
const int retval = abs(_dump_sink(sink_name, sink_timeout, count, interval, key_required, &ctx));
|
||||
if (ctx.v_output && ctx.destroy) {
|
||||
ctx.destroy(ctx.v_output);
|
||||
@@ -206,25 +205,6 @@ static void _signal_handler(int signum) {
|
||||
_g_stop = true;
|
||||
}
|
||||
|
||||
static void _install_signal_handlers(void) {
|
||||
struct sigaction sig_act = {0};
|
||||
|
||||
assert(!sigemptyset(&sig_act.sa_mask));
|
||||
sig_act.sa_handler = _signal_handler;
|
||||
assert(!sigaddset(&sig_act.sa_mask, SIGINT));
|
||||
assert(!sigaddset(&sig_act.sa_mask, SIGTERM));
|
||||
assert(!sigaddset(&sig_act.sa_mask, SIGPIPE));
|
||||
|
||||
US_LOG_DEBUG("Installing SIGINT handler ...");
|
||||
assert(!sigaction(SIGINT, &sig_act, NULL));
|
||||
|
||||
US_LOG_DEBUG("Installing SIGTERM handler ...");
|
||||
assert(!sigaction(SIGTERM, &sig_act, NULL));
|
||||
|
||||
US_LOG_DEBUG("Installing SIGTERM handler ...");
|
||||
assert(!sigaction(SIGPIPE, &sig_act, NULL));
|
||||
}
|
||||
|
||||
static int _dump_sink(
|
||||
const char *sink_name, unsigned sink_timeout,
|
||||
long long count, long double interval,
|
||||
@@ -316,7 +296,7 @@ static void _help(FILE *fp) {
|
||||
SAY("\nuStreamer-dump - Dump uStreamer's memory sink to file");
|
||||
SAY("═════════════════════════════════════════════════════");
|
||||
SAY("Version: %s; license: GPLv3", US_VERSION);
|
||||
SAY("Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com>\n");
|
||||
SAY("Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com>\n");
|
||||
SAY("Example:");
|
||||
SAY("════════");
|
||||
SAY(" ustreamer-dump --sink test --output - \\");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -25,8 +25,8 @@
|
||||
#include "types.h"
|
||||
|
||||
|
||||
#define US_VERSION_MAJOR 5
|
||||
#define US_VERSION_MINOR 53
|
||||
#define US_VERSION_MAJOR 6
|
||||
#define US_VERSION_MINOR 6
|
||||
|
||||
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
||||
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "device.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
@@ -80,12 +81,12 @@ static const struct {
|
||||
{"USERPTR", V4L2_MEMORY_USERPTR},
|
||||
};
|
||||
|
||||
|
||||
static int _device_wait_buffer(us_device_s *dev);
|
||||
static int _device_consume_event(us_device_s *dev);
|
||||
static void _v4l2_buffer_copy(const struct v4l2_buffer *src, struct v4l2_buffer *dest);
|
||||
static bool _device_is_buffer_valid(us_device_s *dev, const struct v4l2_buffer *buf, const u8 *data);
|
||||
static int _device_open_check_cap(us_device_s *dev);
|
||||
static int _device_open_dv_timings(us_device_s *dev);
|
||||
static int _device_apply_dv_timings(us_device_s *dev);
|
||||
static int _device_open_dv_timings(us_device_s *dev, bool apply);
|
||||
static int _device_open_format(us_device_s *dev, bool first);
|
||||
static void _device_open_hw_fps(us_device_s *dev);
|
||||
static void _device_open_jpeg_quality(us_device_s *dev);
|
||||
@@ -93,6 +94,7 @@ static int _device_open_io_method(us_device_s *dev);
|
||||
static int _device_open_io_method_mmap(us_device_s *dev);
|
||||
static int _device_open_io_method_userptr(us_device_s *dev);
|
||||
static int _device_open_queue_buffers(us_device_s *dev);
|
||||
static int _device_open_export_to_dma(us_device_s *dev);
|
||||
static int _device_apply_resolution(us_device_s *dev, uint width, uint height, float hz);
|
||||
|
||||
static void _device_apply_controls(us_device_s *dev);
|
||||
@@ -148,16 +150,16 @@ int us_device_parse_format(const char *str) {
|
||||
return item->format;
|
||||
}
|
||||
});
|
||||
return US_FORMAT_UNKNOWN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
v4l2_std_id us_device_parse_standard(const char *str) {
|
||||
US_ARRAY_ITERATE(_STANDARDS, 1, item, {
|
||||
int us_device_parse_standard(const char *str) {
|
||||
US_ARRAY_ITERATE(_STANDARDS, 0, item, {
|
||||
if (!strcasecmp(item->name, str)) {
|
||||
return item->standard;
|
||||
}
|
||||
});
|
||||
return US_STANDARD_UNKNOWN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int us_device_parse_io_method(const char *str) {
|
||||
@@ -166,22 +168,46 @@ int us_device_parse_io_method(const char *str) {
|
||||
return item->io_method;
|
||||
}
|
||||
});
|
||||
return US_IO_METHOD_UNKNOWN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int us_device_open(us_device_s *dev) {
|
||||
us_device_runtime_s *const run = dev->run;
|
||||
|
||||
if ((run->fd = open(dev->path, O_RDWR|O_NONBLOCK)) < 0) {
|
||||
_D_LOG_PERROR("Can't open device");
|
||||
if (access(dev->path, R_OK | W_OK) < 0) {
|
||||
if (run->open_error_reported != -errno) {
|
||||
run->open_error_reported = -errno; // Don't confuse it with __LINE__
|
||||
US_LOG_PERROR("No access to capture device");
|
||||
}
|
||||
goto tmp_error;
|
||||
}
|
||||
|
||||
_D_LOG_DEBUG("Opening capture device ...");
|
||||
if ((run->fd = open(dev->path, O_RDWR | O_NONBLOCK)) < 0) {
|
||||
_D_LOG_PERROR("Can't capture open device");
|
||||
goto error;
|
||||
}
|
||||
_D_LOG_INFO("Device fd=%d opened", run->fd);
|
||||
_D_LOG_DEBUG("Capture device fd=%d opened", run->fd);
|
||||
|
||||
if (dev->dv_timings && dev->persistent) {
|
||||
_D_LOG_DEBUG("Probing DV-timings or QuerySTD ...");
|
||||
if (_device_open_dv_timings(dev, false) < 0) {
|
||||
const int line = __LINE__;
|
||||
if (run->open_error_reported != line) {
|
||||
run->open_error_reported = line;
|
||||
_D_LOG_ERROR("No signal from source");
|
||||
}
|
||||
goto tmp_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (_device_open_check_cap(dev) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (_device_open_dv_timings(dev) < 0) {
|
||||
if (_device_apply_resolution(dev, dev->width, dev->height, dev->run->hz)) {
|
||||
goto error;
|
||||
}
|
||||
if (dev->dv_timings && _device_open_dv_timings(dev, true) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (_device_open_format(dev, true) < 0) {
|
||||
@@ -195,12 +221,32 @@ int us_device_open(us_device_s *dev) {
|
||||
if (_device_open_queue_buffers(dev) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (dev->dma_export && !us_is_jpeg(run->format)) {
|
||||
// uStreamer doesn't have any component that could handle JPEG capture via DMA
|
||||
run->dma = !_device_open_export_to_dma(dev);
|
||||
if (!run->dma && dev->dma_required) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
_device_apply_controls(dev);
|
||||
|
||||
_D_LOG_DEBUG("Device fd=%d initialized", run->fd);
|
||||
enum v4l2_buf_type type = run->capture_type;
|
||||
if (us_xioctl(run->fd, VIDIOC_STREAMON, &type) < 0) {
|
||||
_D_LOG_PERROR("Can't start capturing");
|
||||
goto error;
|
||||
}
|
||||
run->streamon = true;
|
||||
|
||||
run->open_error_reported = 0;
|
||||
_D_LOG_INFO("Capturing started");
|
||||
return 0;
|
||||
|
||||
tmp_error:
|
||||
us_device_close(dev);
|
||||
return -2;
|
||||
|
||||
error:
|
||||
run->open_error_reported = 0;
|
||||
us_device_close(dev);
|
||||
return -1;
|
||||
}
|
||||
@@ -208,19 +254,30 @@ error:
|
||||
void us_device_close(us_device_s *dev) {
|
||||
us_device_runtime_s *const run = dev->run;
|
||||
|
||||
run->persistent_timeout_reported = false;
|
||||
bool say = false;
|
||||
|
||||
if (run->streamon) {
|
||||
say = true;
|
||||
_D_LOG_DEBUG("Calling VIDIOC_STREAMOFF ...");
|
||||
enum v4l2_buf_type type = run->capture_type;
|
||||
if (us_xioctl(run->fd, VIDIOC_STREAMOFF, &type) < 0) {
|
||||
_D_LOG_PERROR("Can't stop capturing");
|
||||
}
|
||||
run->streamon = false;
|
||||
}
|
||||
|
||||
if (run->hw_bufs != NULL) {
|
||||
_D_LOG_DEBUG("Releasing device buffers ...");
|
||||
say = true;
|
||||
_D_LOG_DEBUG("Releasing HW buffers ...");
|
||||
for (uint index = 0; index < run->n_bufs; ++index) {
|
||||
us_hw_buffer_s *hw = &run->hw_bufs[index];
|
||||
|
||||
US_CLOSE_FD(hw->dma_fd, close);
|
||||
US_CLOSE_FD(hw->dma_fd);
|
||||
|
||||
if (dev->io_method == V4L2_MEMORY_MMAP) {
|
||||
if (hw->raw.allocated > 0 && hw->raw.data != NULL) {
|
||||
if (munmap(hw->raw.data, hw->raw.allocated) < 0) {
|
||||
_D_LOG_PERROR("Can't unmap device buffer=%u", index);
|
||||
_D_LOG_PERROR("Can't unmap HW buffer=%u", index);
|
||||
}
|
||||
}
|
||||
} else { // V4L2_MEMORY_USERPTR
|
||||
@@ -235,105 +292,26 @@ void us_device_close(us_device_s *dev) {
|
||||
run->n_bufs = 0;
|
||||
}
|
||||
|
||||
if (run->fd >= 0) {
|
||||
_D_LOG_DEBUG("Closing device ...");
|
||||
if (close(run->fd) < 0) {
|
||||
_D_LOG_PERROR("Can't close device fd=%d", run->fd);
|
||||
} else {
|
||||
_D_LOG_INFO("Device fd=%d closed", run->fd);
|
||||
}
|
||||
run->fd = -1;
|
||||
US_CLOSE_FD(run->fd);
|
||||
|
||||
if (say) {
|
||||
_D_LOG_INFO("Capturing stopped");
|
||||
}
|
||||
}
|
||||
|
||||
int us_device_export_to_dma(us_device_s *dev) {
|
||||
us_device_runtime_s *const run = dev->run;
|
||||
|
||||
for (uint index = 0; index < run->n_bufs; ++index) {
|
||||
struct v4l2_exportbuffer exp = {
|
||||
.type = run->capture_type,
|
||||
.index = index,
|
||||
};
|
||||
_D_LOG_DEBUG("Exporting device buffer=%u to DMA ...", index);
|
||||
if (us_xioctl(run->fd, VIDIOC_EXPBUF, &exp) < 0) {
|
||||
_D_LOG_PERROR("Can't export device buffer=%u to DMA", index);
|
||||
goto error;
|
||||
}
|
||||
run->hw_bufs[index].dma_fd = exp.fd;
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
for (uint index = 0; index < run->n_bufs; ++index) {
|
||||
US_CLOSE_FD(run->hw_bufs[index].dma_fd, close);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int us_device_switch_capturing(us_device_s *dev, bool enable) {
|
||||
us_device_runtime_s *const run = dev->run;
|
||||
|
||||
if (enable != run->capturing) {
|
||||
enum v4l2_buf_type type = run->capture_type;
|
||||
|
||||
_D_LOG_DEBUG("%s device capturing ...", (enable ? "Starting" : "Stopping"));
|
||||
if (us_xioctl(run->fd, (enable ? VIDIOC_STREAMON : VIDIOC_STREAMOFF), &type) < 0) {
|
||||
_D_LOG_PERROR("Can't %s capturing", (enable ? "start" : "stop"));
|
||||
if (enable) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
run->capturing = enable;
|
||||
_D_LOG_INFO("Capturing %s", (enable ? "started" : "stopped"));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int us_device_select(us_device_s *dev, bool *has_read, bool *has_write, bool *has_error) {
|
||||
us_device_runtime_s *const run = dev->run;
|
||||
|
||||
# define INIT_FD_SET(x_set) \
|
||||
fd_set x_set; FD_ZERO(&x_set); FD_SET(run->fd, &x_set);
|
||||
INIT_FD_SET(read_fds);
|
||||
INIT_FD_SET(write_fds);
|
||||
INIT_FD_SET(error_fds);
|
||||
# undef INIT_FD_SET
|
||||
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = dev->timeout;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
_D_LOG_DEBUG("Calling select() on video device ...");
|
||||
|
||||
int retval = select(run->fd + 1, &read_fds, &write_fds, &error_fds, &timeout);
|
||||
if (retval > 0) {
|
||||
*has_read = FD_ISSET(run->fd, &read_fds);
|
||||
*has_write = FD_ISSET(run->fd, &write_fds);
|
||||
*has_error = FD_ISSET(run->fd, &error_fds);
|
||||
} else {
|
||||
*has_read = false;
|
||||
*has_write = false;
|
||||
*has_error = false;
|
||||
}
|
||||
_D_LOG_DEBUG("Device select() --> %d", retval);
|
||||
|
||||
if (retval > 0) {
|
||||
run->persistent_timeout_reported = false;
|
||||
} else if (retval == 0) {
|
||||
if (dev->persistent) {
|
||||
if (!run->persistent_timeout_reported) {
|
||||
_D_LOG_ERROR("Persistent device timeout (unplugged)");
|
||||
run->persistent_timeout_reported = true;
|
||||
}
|
||||
} else {
|
||||
// Если устройство не персистентное, то таймаут является ошибкой
|
||||
retval = -1;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
|
||||
// Это сложная функция, которая делает сразу много всего, чтобы получить новый фрейм.
|
||||
// - Вызывается _device_wait_buffer() с select() внутри, чтобы подождать новый фрейм
|
||||
// или эвент V4L2. Обработка эвентов более приоритетна, чем кадров.
|
||||
// - Если есть новые фреймы, то пропустить их все, пока не закончатся и вернуть
|
||||
// самый-самый свежий, содержащий при этом валидные данные.
|
||||
// - Если таковых не нашлось, вернуть -2.
|
||||
// - Ошибка -1 возвращается при любых сбоях.
|
||||
|
||||
if (_device_wait_buffer(dev) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
us_device_runtime_s *const run = dev->run;
|
||||
|
||||
*hw = NULL;
|
||||
@@ -349,7 +327,7 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
|
||||
uint skipped = 0;
|
||||
bool broken = false;
|
||||
|
||||
_D_LOG_DEBUG("Grabbing device buffer ...");
|
||||
_D_LOG_DEBUG("Grabbing hw buffer ...");
|
||||
|
||||
do {
|
||||
struct v4l2_buffer new = {0};
|
||||
@@ -365,7 +343,7 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
|
||||
|
||||
if (new_got) {
|
||||
if (new.index >= run->n_bufs) {
|
||||
_D_LOG_ERROR("V4L2 error: grabbed invalid device buffer=%u, n_bufs=%u", new.index, run->n_bufs);
|
||||
_D_LOG_ERROR("V4L2 error: grabbed invalid HW buffer=%u, n_bufs=%u", new.index, run->n_bufs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -373,7 +351,7 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
|
||||
# define FRAME_DATA(x_buf) run->hw_bufs[x_buf.index].raw.data
|
||||
|
||||
if (GRABBED(new)) {
|
||||
_D_LOG_ERROR("V4L2 error: grabbed device buffer=%u is already used", new.index);
|
||||
_D_LOG_ERROR("V4L2 error: grabbed HW buffer=%u is already used", new.index);
|
||||
return -1;
|
||||
}
|
||||
GRABBED(new) = true;
|
||||
@@ -384,9 +362,9 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
|
||||
|
||||
broken = !_device_is_buffer_valid(dev, &new, FRAME_DATA(new));
|
||||
if (broken) {
|
||||
_D_LOG_DEBUG("Releasing device buffer=%u (broken frame) ...", new.index);
|
||||
_D_LOG_DEBUG("Releasing HW buffer=%u (broken frame) ...", new.index);
|
||||
if (us_xioctl(run->fd, VIDIOC_QBUF, &new) < 0) {
|
||||
_D_LOG_PERROR("Can't release device buffer=%u (broken frame)", new.index);
|
||||
_D_LOG_PERROR("Can't release HW buffer=%u (broken frame)", new.index);
|
||||
return -1;
|
||||
}
|
||||
GRABBED(new) = false;
|
||||
@@ -395,7 +373,7 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
|
||||
|
||||
if (buf_got) {
|
||||
if (us_xioctl(run->fd, VIDIOC_QBUF, &buf) < 0) {
|
||||
_D_LOG_PERROR("Can't release device buffer=%u (skipped frame)", buf.index);
|
||||
_D_LOG_PERROR("Can't release HW buffer=%u (skipped frame)", buf.index);
|
||||
return -1;
|
||||
}
|
||||
GRABBED(buf) = false;
|
||||
@@ -417,12 +395,13 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
|
||||
return -2; // If we have only broken frames on this capture session
|
||||
}
|
||||
}
|
||||
_D_LOG_PERROR("Can't grab device buffer");
|
||||
_D_LOG_PERROR("Can't grab HW buffer");
|
||||
return -1;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
*hw = &run->hw_bufs[buf.index];
|
||||
atomic_store(&(*hw)->refs, 0);
|
||||
(*hw)->raw.dma_fd = (*hw)->dma_fd;
|
||||
(*hw)->raw.used = buf.bytesused;
|
||||
(*hw)->raw.width = run->width;
|
||||
@@ -433,36 +412,89 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
|
||||
_v4l2_buffer_copy(&buf, &(*hw)->buf);
|
||||
(*hw)->raw.grab_ts = (ldf)((buf.timestamp.tv_sec * (u64)1000) + (buf.timestamp.tv_usec / 1000)) / 1000;
|
||||
|
||||
_D_LOG_DEBUG("Grabbed new frame: buffer=%u, bytesused=%u, grab_ts=%.3Lf, latency=%.3Lf, skipped=%u",
|
||||
_D_LOG_DEBUG("Grabbed HW buffer=%u: bytesused=%u, grab_ts=%.3Lf, latency=%.3Lf, skipped=%u",
|
||||
buf.index, buf.bytesused, (*hw)->raw.grab_ts, us_get_now_monotonic() - (*hw)->raw.grab_ts, skipped);
|
||||
return buf.index;
|
||||
}
|
||||
|
||||
int us_device_release_buffer(us_device_s *dev, us_hw_buffer_s *hw) {
|
||||
assert(atomic_load(&hw->refs) == 0);
|
||||
const uint index = hw->buf.index;
|
||||
_D_LOG_DEBUG("Releasing device buffer=%u ...", index);
|
||||
_D_LOG_DEBUG("Releasing HW buffer=%u ...", index);
|
||||
if (us_xioctl(dev->run->fd, VIDIOC_QBUF, &hw->buf) < 0) {
|
||||
_D_LOG_PERROR("Can't release device buffer=%u", index);
|
||||
_D_LOG_PERROR("Can't release HW buffer=%u", index);
|
||||
return -1;
|
||||
}
|
||||
hw->grabbed = false;
|
||||
_D_LOG_DEBUG("HW buffer=%u released", index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int us_device_consume_event(us_device_s *dev) {
|
||||
struct v4l2_event event;
|
||||
_D_LOG_DEBUG("Consuming V4L2 event ...");
|
||||
if (us_xioctl(dev->run->fd, VIDIOC_DQEVENT, &event) == 0) {
|
||||
switch (event.type) {
|
||||
case V4L2_EVENT_SOURCE_CHANGE:
|
||||
_D_LOG_INFO("Got V4L2_EVENT_SOURCE_CHANGE: source changed");
|
||||
return -1;
|
||||
case V4L2_EVENT_EOS:
|
||||
_D_LOG_INFO("Got V4L2_EVENT_EOS: end of stream (ignored)");
|
||||
return 0;
|
||||
void us_device_buffer_incref(us_hw_buffer_s *hw) {
|
||||
atomic_fetch_add(&hw->refs, 1);
|
||||
}
|
||||
|
||||
void us_device_buffer_decref(us_hw_buffer_s *hw) {
|
||||
atomic_fetch_sub(&hw->refs, 1);
|
||||
}
|
||||
|
||||
int _device_wait_buffer(us_device_s *dev) {
|
||||
us_device_runtime_s *const run = dev->run;
|
||||
|
||||
# define INIT_FD_SET(x_set) \
|
||||
fd_set x_set; FD_ZERO(&x_set); FD_SET(run->fd, &x_set);
|
||||
INIT_FD_SET(read_fds);
|
||||
INIT_FD_SET(error_fds);
|
||||
# undef INIT_FD_SET
|
||||
|
||||
// Раньше мы проверяли и has_write, но потом выяснилось, что libcamerify зачем-то
|
||||
// генерирует эвенты на запись, вероятно ошибочно. Судя по всему, игнорирование
|
||||
// has_write не делает никому плохо.
|
||||
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = dev->timeout;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
_D_LOG_DEBUG("Calling select() on video device ...");
|
||||
|
||||
bool has_read = false;
|
||||
bool has_error = false;
|
||||
const int selected = select(run->fd + 1, &read_fds, NULL, &error_fds, &timeout);
|
||||
if (selected > 0) {
|
||||
has_read = FD_ISSET(run->fd, &read_fds);
|
||||
has_error = FD_ISSET(run->fd, &error_fds);
|
||||
}
|
||||
_D_LOG_DEBUG("Device select() --> %d; has_read=%d, has_error=%d", selected, has_read, has_error);
|
||||
|
||||
if (selected < 0) {
|
||||
if (errno != EINTR) {
|
||||
_D_LOG_PERROR("Device select() error");
|
||||
}
|
||||
return -1;
|
||||
} else if (selected == 0) {
|
||||
_D_LOG_ERROR("Device select() timeout");
|
||||
return -1;
|
||||
} else {
|
||||
_D_LOG_PERROR("Got some V4L2 device event, but where is it? ");
|
||||
if (has_error && _device_consume_event(dev) < 0) {
|
||||
return -1; // Restart required
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _device_consume_event(us_device_s *dev) {
|
||||
struct v4l2_event event;
|
||||
if (us_xioctl(dev->run->fd, VIDIOC_DQEVENT, &event) < 0) {
|
||||
_D_LOG_PERROR("Can't consume V4L2 event");
|
||||
return -1;
|
||||
}
|
||||
switch (event.type) {
|
||||
case V4L2_EVENT_SOURCE_CHANGE:
|
||||
_D_LOG_INFO("Got V4L2_EVENT_SOURCE_CHANGE: Source changed");
|
||||
return -1;
|
||||
case V4L2_EVENT_EOS:
|
||||
_D_LOG_INFO("Got V4L2_EVENT_EOS: End of stream");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -565,68 +597,81 @@ static int _device_open_check_cap(us_device_s *dev) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _device_open_dv_timings(us_device_s *dev) {
|
||||
_device_apply_resolution(dev, dev->width, dev->height, dev->run->hz);
|
||||
if (dev->dv_timings) {
|
||||
_D_LOG_DEBUG("Using DV-timings");
|
||||
static int _device_open_dv_timings(us_device_s *dev, bool apply) {
|
||||
// Just probe only if @apply is false
|
||||
|
||||
if (_device_apply_dv_timings(dev) < 0) {
|
||||
return -1;
|
||||
}
|
||||
const us_device_runtime_s *const run = dev->run;
|
||||
|
||||
struct v4l2_event_subscription sub = {.type = V4L2_EVENT_SOURCE_CHANGE};
|
||||
_D_LOG_DEBUG("Subscribing to DV-timings events ...")
|
||||
if (us_xioctl(dev->run->fd, VIDIOC_SUBSCRIBE_EVENT, &sub) < 0) {
|
||||
_D_LOG_PERROR("Can't subscribe to DV-timings events");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _device_apply_dv_timings(us_device_s *dev) {
|
||||
us_device_runtime_s *const run = dev->run; // cppcheck-suppress constVariablePointer
|
||||
int dv_errno = 0;
|
||||
|
||||
struct v4l2_dv_timings dv = {0};
|
||||
|
||||
_D_LOG_DEBUG("Calling us_xioctl(VIDIOC_QUERY_DV_TIMINGS) ...");
|
||||
if (us_xioctl(run->fd, VIDIOC_QUERY_DV_TIMINGS, &dv) == 0) {
|
||||
float hz = 0;
|
||||
if (dv.type == V4L2_DV_BT_656_1120) {
|
||||
// See v4l2_print_dv_timings() in the kernel
|
||||
const uint htot = V4L2_DV_BT_FRAME_WIDTH(&dv.bt);
|
||||
const uint vtot = V4L2_DV_BT_FRAME_HEIGHT(&dv.bt) / (dv.bt.interlaced ? 2 : 1);
|
||||
const uint fps = ((htot * vtot) > 0 ? ((100 * (u64)dv.bt.pixelclock)) / (htot * vtot) : 0);
|
||||
hz = (fps / 100) + (fps % 100) / 100.0;
|
||||
_D_LOG_INFO("Got new DV-timings: %ux%u%s%.02f, pixclk=%llu, vsync=%u, hsync=%u",
|
||||
dv.bt.width, dv.bt.height, (dv.bt.interlaced ? "i" : "p"), hz,
|
||||
(ull)dv.bt.pixelclock, dv.bt.vsync, dv.bt.hsync); // See #11 about %llu
|
||||
} else {
|
||||
_D_LOG_INFO("Got new DV-timings: %ux%u, pixclk=%llu, vsync=%u, hsync=%u",
|
||||
dv.bt.width, dv.bt.height,
|
||||
(ull)dv.bt.pixelclock, dv.bt.vsync, dv.bt.hsync);
|
||||
}
|
||||
|
||||
_D_LOG_DEBUG("Calling us_xioctl(VIDIOC_S_DV_TIMINGS) ...");
|
||||
if (us_xioctl(run->fd, VIDIOC_S_DV_TIMINGS, &dv) < 0) {
|
||||
_D_LOG_PERROR("Failed to set DV-timings");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_device_apply_resolution(dev, dv.bt.width, dv.bt.height, hz) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
_D_LOG_DEBUG("Calling us_xioctl(VIDIOC_QUERYSTD) ...");
|
||||
if (us_xioctl(run->fd, VIDIOC_QUERYSTD, &dev->standard) == 0) {
|
||||
_D_LOG_INFO("Applying the new VIDIOC_S_STD: %s ...", _standard_to_string(dev->standard));
|
||||
if (us_xioctl(run->fd, VIDIOC_S_STD, &dev->standard) < 0) {
|
||||
_D_LOG_PERROR("Can't set video standard");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
_D_LOG_DEBUG("Querying DV-timings (apply=%u) ...", apply);
|
||||
if (us_xioctl(run->fd, VIDIOC_QUERY_DV_TIMINGS, &dv) < 0) {
|
||||
// TC358743 errors here (see in the kernel: drivers/media/i2c/tc358743.c):
|
||||
// - ENOLINK: No valid signal (SYS_STATUS & MASK_S_TMDS)
|
||||
// - ENOLCK: No sync on signal (SYS_STATUS & MASK_S_SYNC)
|
||||
dv_errno = errno;
|
||||
goto querystd;
|
||||
} else if (!apply) {
|
||||
goto probe_only;
|
||||
}
|
||||
|
||||
float hz = 0;
|
||||
if (dv.type == V4L2_DV_BT_656_1120) {
|
||||
// See v4l2_print_dv_timings() in the kernel
|
||||
const uint htot = V4L2_DV_BT_FRAME_WIDTH(&dv.bt);
|
||||
const uint vtot = V4L2_DV_BT_FRAME_HEIGHT(&dv.bt) / (dv.bt.interlaced ? 2 : 1);
|
||||
const uint fps = ((htot * vtot) > 0 ? ((100 * (u64)dv.bt.pixelclock)) / (htot * vtot) : 0);
|
||||
hz = (fps / 100) + (fps % 100) / 100.0;
|
||||
_D_LOG_INFO("Detected DV-timings: %ux%u%s%.02f, pixclk=%llu, vsync=%u, hsync=%u",
|
||||
dv.bt.width, dv.bt.height, (dv.bt.interlaced ? "i" : "p"), hz,
|
||||
(ull)dv.bt.pixelclock, dv.bt.vsync, dv.bt.hsync); // See #11 about %llu
|
||||
} else {
|
||||
_D_LOG_INFO("Detected DV-timings: %ux%u, pixclk=%llu, vsync=%u, hsync=%u",
|
||||
dv.bt.width, dv.bt.height,
|
||||
(ull)dv.bt.pixelclock, dv.bt.vsync, dv.bt.hsync);
|
||||
}
|
||||
|
||||
_D_LOG_DEBUG("Applying DV-timings ...");
|
||||
if (us_xioctl(run->fd, VIDIOC_S_DV_TIMINGS, &dv) < 0) {
|
||||
_D_LOG_PERROR("Failed to apply DV-timings");
|
||||
return -1;
|
||||
}
|
||||
if (_device_apply_resolution(dev, dv.bt.width, dv.bt.height, hz) < 0) {
|
||||
return -1;
|
||||
}
|
||||
goto subscribe;
|
||||
|
||||
querystd:
|
||||
_D_LOG_DEBUG("Failed to query DV-timings, trying QuerySTD ...");
|
||||
if (us_xioctl(run->fd, VIDIOC_QUERYSTD, &dev->standard) < 0) {
|
||||
if (apply) {
|
||||
char *std_error = us_errno_to_string(errno); // Read the errno first
|
||||
char *dv_error = us_errno_to_string(dv_errno);
|
||||
_D_LOG_ERROR("Failed to query DV-timings (%s) and QuerySTD (%s)", dv_error, std_error);
|
||||
free(dv_error);
|
||||
free(std_error);
|
||||
}
|
||||
return -1;
|
||||
} else if (!apply) {
|
||||
goto probe_only;
|
||||
}
|
||||
if (us_xioctl(run->fd, VIDIOC_S_STD, &dev->standard) < 0) {
|
||||
_D_LOG_PERROR("Can't set apply standard: %s", _standard_to_string(dev->standard));
|
||||
return -1;
|
||||
}
|
||||
_D_LOG_DEBUG("Applied new video standard: %s", _standard_to_string(dev->standard));
|
||||
|
||||
subscribe:
|
||||
; // Empty statement for the goto label above
|
||||
struct v4l2_event_subscription sub = {.type = V4L2_EVENT_SOURCE_CHANGE};
|
||||
_D_LOG_DEBUG("Subscribing to V4L2_EVENT_SOURCE_CHANGE ...")
|
||||
if (us_xioctl(dev->run->fd, VIDIOC_SUBSCRIBE_EVENT, &sub) < 0) {
|
||||
_D_LOG_PERROR("Can't subscribe to V4L2_EVENT_SOURCE_CHANGE");
|
||||
return -1;
|
||||
}
|
||||
|
||||
probe_only:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -689,7 +734,7 @@ static int _device_open_format(us_device_s *dev, bool first) {
|
||||
_format_to_string_supported(FMT(pixelformat)));
|
||||
|
||||
char *format_str;
|
||||
if ((format_str = (char *)_format_to_string_nullable(FMT(pixelformat))) != NULL) {
|
||||
if ((format_str = (char*)_format_to_string_nullable(FMT(pixelformat))) != NULL) {
|
||||
_D_LOG_INFO("Falling back to format=%s", format_str);
|
||||
} else {
|
||||
char fourcc_str[8];
|
||||
@@ -837,6 +882,7 @@ static int _device_open_io_method_mmap(us_device_s *dev) {
|
||||
}
|
||||
|
||||
us_hw_buffer_s *hw = &run->hw_bufs[run->n_bufs];
|
||||
atomic_init(&hw->refs, 0);
|
||||
const uz buf_size = (run->capture_mplane ? buf.m.planes[0].length : buf.length);
|
||||
const off_t buf_offset = (run->capture_mplane ? buf.m.planes[0].m.mem_offset : buf.m.offset);
|
||||
|
||||
@@ -931,6 +977,30 @@ static int _device_open_queue_buffers(us_device_s *dev) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _device_open_export_to_dma(us_device_s *dev) {
|
||||
us_device_runtime_s *const run = dev->run;
|
||||
|
||||
for (uint index = 0; index < run->n_bufs; ++index) {
|
||||
struct v4l2_exportbuffer exp = {
|
||||
.type = run->capture_type,
|
||||
.index = index,
|
||||
};
|
||||
_D_LOG_DEBUG("Exporting device buffer=%u to DMA ...", index);
|
||||
if (us_xioctl(run->fd, VIDIOC_EXPBUF, &exp) < 0) {
|
||||
_D_LOG_PERROR("Can't export device buffer=%u to DMA", index);
|
||||
goto error;
|
||||
}
|
||||
run->hw_bufs[index].dma_fd = exp.fd;
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
for (uint index = 0; index < run->n_bufs; ++index) {
|
||||
US_CLOSE_FD(run->hw_bufs[index].dma_fd);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _device_apply_resolution(us_device_s *dev, uint width, uint height, float hz) {
|
||||
// Тут VIDEO_MIN_* не используются из-за странностей минимального разрешения при отсутствии сигнала
|
||||
// у некоторых устройств, например TC358743
|
||||
@@ -1066,7 +1136,7 @@ static const char *_standard_to_string(v4l2_std_id standard) {
|
||||
return item->name;
|
||||
}
|
||||
});
|
||||
return _STANDARDS[0].name;
|
||||
return "???";
|
||||
}
|
||||
|
||||
static const char *_io_method_to_string_supported(enum v4l2_memory io_method) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#include "types.h"
|
||||
@@ -29,20 +31,15 @@
|
||||
|
||||
|
||||
#define US_VIDEO_MIN_WIDTH ((uint)160)
|
||||
#define US_VIDEO_MAX_WIDTH ((uint)15360)
|
||||
#define US_VIDEO_MAX_WIDTH ((uint)15360) // Remember about stream->run->http_capture_state;
|
||||
|
||||
#define US_VIDEO_MIN_HEIGHT ((uint)120)
|
||||
#define US_VIDEO_MAX_HEIGHT ((uint)8640)
|
||||
|
||||
#define US_VIDEO_MAX_FPS ((uint)120)
|
||||
|
||||
#define US_STANDARD_UNKNOWN V4L2_STD_UNKNOWN
|
||||
#define US_STANDARDS_STR "PAL, NTSC, SECAM"
|
||||
|
||||
#define US_FORMAT_UNKNOWN -1
|
||||
#define US_FORMATS_STR "YUYV, YVYU, UYVY, RGB565, RGB24, BGR24, MJPEG, JPEG"
|
||||
|
||||
#define US_IO_METHOD_UNKNOWN -1
|
||||
#define US_IO_METHODS_STR "MMAP, USERPTR"
|
||||
|
||||
|
||||
@@ -51,6 +48,7 @@ typedef struct {
|
||||
struct v4l2_buffer buf;
|
||||
int dma_fd;
|
||||
bool grabbed;
|
||||
atomic_int refs;
|
||||
} us_hw_buffer_s;
|
||||
|
||||
typedef struct {
|
||||
@@ -65,10 +63,11 @@ typedef struct {
|
||||
uz raw_size;
|
||||
uint n_bufs;
|
||||
us_hw_buffer_s *hw_bufs;
|
||||
bool dma;
|
||||
enum v4l2_buf_type capture_type;
|
||||
bool capture_mplane;
|
||||
bool capturing;
|
||||
bool persistent_timeout_reported;
|
||||
bool streamon;
|
||||
int open_error_reported;
|
||||
} us_device_runtime_s;
|
||||
|
||||
typedef enum {
|
||||
@@ -110,6 +109,8 @@ typedef struct {
|
||||
enum v4l2_memory io_method;
|
||||
bool dv_timings;
|
||||
uint n_bufs;
|
||||
bool dma_export;
|
||||
bool dma_required;
|
||||
uint desired_fps;
|
||||
uz min_frame_size;
|
||||
bool persistent;
|
||||
@@ -123,15 +124,14 @@ us_device_s *us_device_init(void);
|
||||
void us_device_destroy(us_device_s *dev);
|
||||
|
||||
int us_device_parse_format(const char *str);
|
||||
v4l2_std_id us_device_parse_standard(const char *str);
|
||||
int us_device_parse_standard(const char *str);
|
||||
int us_device_parse_io_method(const char *str);
|
||||
|
||||
int us_device_open(us_device_s *dev);
|
||||
void us_device_close(us_device_s *dev);
|
||||
|
||||
int us_device_export_to_dma(us_device_s *dev);
|
||||
int us_device_switch_capturing(us_device_s *dev, bool enable);
|
||||
int us_device_select(us_device_s *dev, bool *has_read, bool *has_write, bool *has_error);
|
||||
int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw);
|
||||
int us_device_release_buffer(us_device_s *dev, us_hw_buffer_s *hw);
|
||||
int us_device_consume_event(us_device_s *dev);
|
||||
|
||||
void us_device_buffer_incref(us_hw_buffer_s *hw);
|
||||
void us_device_buffer_decref(us_hw_buffer_s *hw);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -74,7 +74,7 @@ void us_frame_copy(const us_frame_s *src, us_frame_s *dest) {
|
||||
bool us_frame_compare(const us_frame_s *a, const us_frame_s *b) {
|
||||
return (
|
||||
a->allocated && b->allocated
|
||||
&& US_FRAME_COMPARE_META_USED_NOTS(a, b)
|
||||
&& US_FRAME_COMPARE_GEOMETRY(a, b)
|
||||
&& !memcmp(a->data, b->data, b->used)
|
||||
);
|
||||
}
|
||||
@@ -99,6 +99,10 @@ uint us_frame_get_padding(const us_frame_s *frame) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool us_is_jpeg(uint format) {
|
||||
return (format == V4L2_PIX_FMT_JPEG || format == V4L2_PIX_FMT_MJPEG);
|
||||
}
|
||||
|
||||
const char *us_fourcc_to_string(uint format, char *buf, uz size) {
|
||||
assert(size >= 8);
|
||||
buf[0] = format & 0x7F;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -22,8 +22,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "tools.h"
|
||||
|
||||
@@ -41,7 +39,6 @@ typedef struct {
|
||||
// Stride is a bytesperline in V4L2
|
||||
// https://www.kernel.org/doc/html/v4.14/media/uapi/v4l/pixfmt-v4l2.html
|
||||
// https://medium.com/@oleg.shipitko/what-does-stride-mean-in-image-processing-bba158a72bcd
|
||||
|
||||
bool online;
|
||||
bool key;
|
||||
uint gop;
|
||||
@@ -60,17 +57,16 @@ typedef struct {
|
||||
x_dest->online = x_src->online; \
|
||||
x_dest->key = x_src->key; \
|
||||
x_dest->gop = x_src->gop; \
|
||||
\
|
||||
x_dest->grab_ts = x_src->grab_ts; \
|
||||
x_dest->encode_begin_ts = x_src->encode_begin_ts; \
|
||||
x_dest->encode_end_ts = x_src->encode_end_ts; \
|
||||
}
|
||||
|
||||
static inline void us_frame_copy_meta(const us_frame_s *src, us_frame_s *dest) {
|
||||
US_FRAME_COPY_META(src, dest);
|
||||
}
|
||||
|
||||
#define US_FRAME_COMPARE_META_USED_NOTS(x_a, x_b) ( \
|
||||
#define US_FRAME_COMPARE_GEOMETRY(x_a, x_b) ( \
|
||||
/* Compare the used size and significant meta (no timings) */ \
|
||||
x_a->used == x_b->used \
|
||||
\
|
||||
&& x_a->width == x_b->width \
|
||||
&& x_a->height == x_b->height \
|
||||
&& x_a->format == x_b->format \
|
||||
@@ -83,7 +79,7 @@ static inline void us_frame_copy_meta(const us_frame_s *src, us_frame_s *dest) {
|
||||
|
||||
static inline void us_frame_encoding_begin(const us_frame_s *src, us_frame_s *dest, uint format) {
|
||||
assert(src->used > 0);
|
||||
us_frame_copy_meta(src, dest);
|
||||
US_FRAME_COPY_META(src, dest);
|
||||
dest->encode_begin_ts = us_get_now_monotonic();
|
||||
dest->format = format;
|
||||
dest->stride = 0;
|
||||
@@ -108,8 +104,5 @@ bool us_frame_compare(const us_frame_s *a, const us_frame_s *b);
|
||||
|
||||
uint us_frame_get_padding(const us_frame_s *frame);
|
||||
|
||||
bool us_is_jpeg(uint format);
|
||||
const char *us_fourcc_to_string(uint format, char *buf, uz size);
|
||||
|
||||
static inline bool us_is_jpeg(uint format) {
|
||||
return (format == V4L2_PIX_FMT_JPEG || format == V4L2_PIX_FMT_MJPEG);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -20,7 +20,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "ftext.h"
|
||||
#include "frametext.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -28,32 +28,62 @@
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#include "../libs/tools.h"
|
||||
#include "../libs/frame.h"
|
||||
|
||||
#include "ftext_font.h"
|
||||
#include "tools.h"
|
||||
#include "frame.h"
|
||||
#include "frametext_font.h"
|
||||
|
||||
|
||||
static void _ftext_draw_line(
|
||||
us_ftext_s *ft, const char *line,
|
||||
static void _frametext_draw_line(
|
||||
us_frametext_s *ft, const char *line,
|
||||
uint scale_x, uint scale_y,
|
||||
uint start_x, uint start_y);
|
||||
|
||||
|
||||
us_ftext_s *us_ftext_init(void) {
|
||||
us_ftext_s *ft;
|
||||
us_frametext_s *us_frametext_init(void) {
|
||||
us_frametext_s *ft;
|
||||
US_CALLOC(ft, 1);
|
||||
ft->frame = us_frame_init();
|
||||
return ft;
|
||||
}
|
||||
|
||||
void us_ftext_destroy(us_ftext_s *ft) {
|
||||
void us_frametext_destroy(us_frametext_s *ft) {
|
||||
us_frame_destroy(ft->frame);
|
||||
US_DELETE(ft->text, free);
|
||||
free(ft);
|
||||
}
|
||||
|
||||
void us_ftext_draw(us_ftext_s *ft, const char *text, uint width, uint height) {
|
||||
/*
|
||||
Every character in the font is encoded row-wise in 8 bytes.
|
||||
The least significant bit of each byte corresponds to the first pixel in a row.
|
||||
The character 'A' (0x41 / 65) is encoded as { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}
|
||||
|
||||
0x0C => 0000 1100 => ..XX....
|
||||
0X1E => 0001 1110 => .XXXX...
|
||||
0x33 => 0011 0011 => XX..XX..
|
||||
0x33 => 0011 0011 => XX..XX..
|
||||
0x3F => 0011 1111 => xxxxxx..
|
||||
0x33 => 0011 0011 => XX..XX..
|
||||
0x33 => 0011 0011 => XX..XX..
|
||||
0x00 => 0000 0000 => ........
|
||||
|
||||
To access the nth pixel in a row, right-shift by n.
|
||||
|
||||
. . X X . . . .
|
||||
| | | | | | | |
|
||||
(0x0C >> 0) & 1 == 0-+ | | | | | | |
|
||||
(0x0C >> 1) & 1 == 0---+ | | | | | |
|
||||
(0x0C >> 2) & 1 == 1-----+ | | | | |
|
||||
(0x0C >> 3) & 1 == 1-------+ | | | |
|
||||
(0x0C >> 4) & 1 == 0---------+ | | |
|
||||
(0x0C >> 5) & 1 == 0-----------+ | |
|
||||
(0x0C >> 6) & 1 == 0-------------+ |
|
||||
(0x0C >> 7) & 1 == 0---------------+
|
||||
*/
|
||||
|
||||
void us_frametext_draw(us_frametext_s *ft, const char *text, uint width, uint height) {
|
||||
assert(width > 0);
|
||||
assert(height > 0);
|
||||
|
||||
us_frame_s *const frame = ft->frame;
|
||||
|
||||
if (
|
||||
@@ -110,7 +140,7 @@ void us_ftext_draw(us_ftext_s *ft, const char *text, uint width, uint height) {
|
||||
const uint start_x = (frame->width >= line_width
|
||||
? ((frame->width - line_width) / 2)
|
||||
: 0);
|
||||
_ftext_draw_line(ft, line, scale_x, scale_y, start_x, start_y + n_line * 8 * scale_y);
|
||||
_frametext_draw_line(ft, line, scale_x, scale_y, start_x, start_y + n_line * 8 * scale_y);
|
||||
++n_line;
|
||||
}
|
||||
|
||||
@@ -118,8 +148,8 @@ empty:
|
||||
free(str);
|
||||
}
|
||||
|
||||
void _ftext_draw_line(
|
||||
us_ftext_s *ft, const char *line,
|
||||
void _frametext_draw_line(
|
||||
us_frametext_s *ft, const char *line,
|
||||
uint scale_x, uint scale_y,
|
||||
uint start_x, uint start_y) {
|
||||
|
||||
@@ -139,16 +169,16 @@ void _ftext_draw_line(
|
||||
break;
|
||||
}
|
||||
|
||||
const u8 ch = US_MIN((u8)line[ch_x / 8 / scale_x], sizeof(US_FTEXT_FONT) / 8 - 1);
|
||||
const u8 ch = US_MIN((u8)line[ch_x / 8 / scale_x], sizeof(US_FRAMETEXT_FONT) / 8 - 1);
|
||||
const uint ch_byte = (ch_y / scale_y) % 8;
|
||||
const uint ch_bit = (ch_x / scale_x) % 8;
|
||||
const bool pix_on = !!(US_FTEXT_FONT[ch][ch_byte] & (1 << ch_bit));
|
||||
const bool pix_on = !!(US_FRAMETEXT_FONT[ch][ch_byte] & (1 << ch_bit));
|
||||
|
||||
u8 *const b = &frame->data[offset]; // XXX: Big endian for Raspberry
|
||||
u8 *const g = b + 1;
|
||||
u8 *const r = g + 1;
|
||||
u8 *const r = &frame->data[offset];
|
||||
u8 *const g = r + 1;
|
||||
u8 *const b = r + 2;
|
||||
|
||||
*r = pix_on * 0x51;
|
||||
*r = pix_on * 0x65; // RGB/BGR-friendly
|
||||
*g = pix_on * 0x65;
|
||||
*b = pix_on * 0x65;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -23,17 +23,17 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../libs/types.h"
|
||||
#include "../libs/frame.h"
|
||||
#include "types.h"
|
||||
#include "frame.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
char *text;
|
||||
us_frame_s *frame;
|
||||
} us_ftext_s;
|
||||
} us_frametext_s;
|
||||
|
||||
|
||||
us_ftext_s *us_ftext_init(void);
|
||||
void us_ftext_destroy(us_ftext_s *ft);
|
||||
us_frametext_s *us_frametext_init(void);
|
||||
void us_frametext_destroy(us_frametext_s *ft);
|
||||
|
||||
void us_ftext_draw(us_ftext_s *ft, const char *text, uint width, uint height);
|
||||
void us_frametext_draw(us_frametext_s *ft, const char *text, uint width, uint height);
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -20,11 +20,15 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "ftext_font.h"
|
||||
#include "frametext_font.h"
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
const u8 US_FTEXT_FONT[128][8] = {
|
||||
const u8 US_FRAMETEXT_FONT[128][8] = {
|
||||
// https://github.com/dhepper/font8x8/blob/master/font8x8_basic.h
|
||||
// Author: Daniel Hepper <daniel@hepper.net>
|
||||
// License: Public Domain
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul)
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../libs/types.h"
|
||||
#include "types.h"
|
||||
|
||||
|
||||
extern const u8 US_FTEXT_FONT[128][8];
|
||||
extern const u8 US_FRAMETEXT_FONT[128][8];
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -56,6 +56,11 @@ us_memsink_s *us_memsink_init(
|
||||
|
||||
US_LOG_INFO("Using %s-sink: %s", name, obj);
|
||||
|
||||
if ((sink->data_size = us_memsink_calculate_size(obj)) == 0) {
|
||||
US_LOG_ERROR("%s-sink: Invalid object suffix", name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
const mode_t mask = umask(0);
|
||||
sink->fd = shm_open(sink->obj, (server ? O_RDWR | O_CREAT : O_RDWR), mode);
|
||||
umask(mask);
|
||||
@@ -65,12 +70,12 @@ us_memsink_s *us_memsink_init(
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (sink->server && ftruncate(sink->fd, sizeof(us_memsink_shared_s)) < 0) {
|
||||
if (sink->server && ftruncate(sink->fd, sizeof(us_memsink_shared_s) + sink->data_size) < 0) {
|
||||
US_LOG_PERROR("%s-sink: Can't truncate shared memory", name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((sink->mem = us_memsink_shared_map(sink->fd)) == NULL) {
|
||||
if ((sink->mem = us_memsink_shared_map(sink->fd, sink->data_size)) == NULL) {
|
||||
US_LOG_PERROR("%s-sink: Can't mmap shared memory", name);
|
||||
goto error;
|
||||
}
|
||||
@@ -83,7 +88,7 @@ error:
|
||||
|
||||
void us_memsink_destroy(us_memsink_s *sink) {
|
||||
if (sink->mem != NULL) {
|
||||
if (us_memsink_shared_unmap(sink->mem) < 0) {
|
||||
if (us_memsink_shared_unmap(sink->mem, sink->data_size) < 0) {
|
||||
US_LOG_PERROR("%s-sink: Can't unmap shared memory", sink->name);
|
||||
}
|
||||
}
|
||||
@@ -101,16 +106,35 @@ void us_memsink_destroy(us_memsink_s *sink) {
|
||||
}
|
||||
|
||||
bool us_memsink_server_check(us_memsink_s *sink, const us_frame_s *frame) {
|
||||
// Return true (the need to write to memsink) on any of these conditions:
|
||||
// - EWOULDBLOCK - we have an active client;
|
||||
// - Incorrect magic or version - need to first write;
|
||||
// - We have some active clients by last_client_ts;
|
||||
// - Frame meta differs (like size, format, but not timestamp).
|
||||
// Если frame == NULL, то только проверяем наличие клиентов
|
||||
// или необходимость инициализировать память.
|
||||
|
||||
assert(sink->server);
|
||||
|
||||
if (sink->mem->magic != US_MEMSINK_MAGIC || sink->mem->version != US_MEMSINK_VERSION) {
|
||||
// Если регион памяти не был инициализирован, то нужно что-то туда положить.
|
||||
// Блокировка не нужна, потому что только сервер пишет в эти переменные.
|
||||
return true;
|
||||
}
|
||||
|
||||
const ldf unsafe_ts = sink->mem->last_client_ts;
|
||||
if (unsafe_ts != sink->unsafe_last_client_ts) {
|
||||
// Клиент пишет в синке свою отметку last_client_ts при любом действии.
|
||||
// Мы не берем блокировку здесь, а просто проверяем, является ли это число тем же самым,
|
||||
// что было прочитано нами в предыдущих итерациях. Значению не нужно быть консистентным,
|
||||
// и даже если мы прочитали мусор из-за гонки в памяти между чтением здеси и записью
|
||||
// из клиента, мы все равно можем сделать вывод, есть ли у нас клиенты вообще.
|
||||
// Если число число поменялось то у нас точно есть клиенты и дальнейшие проверки
|
||||
// проводить не требуется. Если же число неизменно, то стоит поставить блокировку
|
||||
// и проверить, нужно ли записать что-нибудь в память для инициализации фрейма.
|
||||
sink->unsafe_last_client_ts = unsafe_ts;
|
||||
atomic_store(&sink->has_clients, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (flock(sink->fd, LOCK_EX | LOCK_NB) < 0) {
|
||||
if (errno == EWOULDBLOCK) {
|
||||
// Есть живой клиент, который прямо сейчас взял блокировку и читает фрейм из синка
|
||||
atomic_store(&sink->has_clients, true);
|
||||
return true;
|
||||
}
|
||||
@@ -118,10 +142,7 @@ bool us_memsink_server_check(us_memsink_s *sink, const us_frame_s *frame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sink->mem->magic != US_MEMSINK_MAGIC || sink->mem->version != US_MEMSINK_VERSION) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Проверяем, есть ли у нас живой клиент по таймауту
|
||||
const bool has_clients = (sink->mem->last_client_ts + sink->client_ttl > us_get_now_monotonic());
|
||||
atomic_store(&sink->has_clients, has_clients);
|
||||
|
||||
@@ -129,31 +150,39 @@ bool us_memsink_server_check(us_memsink_s *sink, const us_frame_s *frame) {
|
||||
US_LOG_PERROR("%s-sink: Can't unlock memory", sink->name);
|
||||
return false;
|
||||
}
|
||||
return (has_clients || !US_FRAME_COMPARE_META_USED_NOTS(sink->mem, frame));;
|
||||
if (has_clients) {
|
||||
return true;
|
||||
}
|
||||
if (frame != NULL && !US_FRAME_COMPARE_GEOMETRY(sink->mem, frame)) {
|
||||
// Если есть изменения в геометрии/формате фрейма, то их тоже нобходимо сразу записать в синк
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int us_memsink_server_put(us_memsink_s *sink, const us_frame_s *frame, bool *key_requested) {
|
||||
assert(sink->server);
|
||||
|
||||
const long double now = us_get_now_monotonic();
|
||||
const ldf now = us_get_now_monotonic();
|
||||
|
||||
if (frame->used > US_MEMSINK_MAX_DATA) {
|
||||
if (frame->used > sink->data_size) {
|
||||
US_LOG_ERROR("%s-sink: Can't put frame: is too big (%zu > %zu)",
|
||||
sink->name, frame->used, US_MEMSINK_MAX_DATA);
|
||||
sink->name, frame->used, sink->data_size);
|
||||
return 0; // -2
|
||||
}
|
||||
|
||||
if (us_flock_timedwait_monotonic(sink->fd, 1) == 0) {
|
||||
US_LOG_VERBOSE("%s-sink: >>>>> Exposing new frame ...", sink->name);
|
||||
|
||||
sink->last_id = us_get_now_id();
|
||||
sink->mem->id = sink->last_id;
|
||||
sink->mem->id = us_get_now_id();
|
||||
if (sink->mem->key_requested && frame->key) {
|
||||
sink->mem->key_requested = false;
|
||||
}
|
||||
*key_requested = sink->mem->key_requested;
|
||||
if (key_requested != NULL) { // We don't need it for non-H264 sinks
|
||||
*key_requested = sink->mem->key_requested;
|
||||
}
|
||||
|
||||
memcpy(sink->mem->data, frame->data, frame->used);
|
||||
memcpy(us_memsink_get_data(sink->mem), frame->data, frame->used);
|
||||
sink->mem->used = frame->used;
|
||||
US_FRAME_COPY_META(frame, sink->mem);
|
||||
|
||||
@@ -179,7 +208,7 @@ int us_memsink_server_put(us_memsink_s *sink, const us_frame_s *frame, bool *key
|
||||
return 0;
|
||||
}
|
||||
|
||||
int us_memsink_client_get(us_memsink_s *sink, us_frame_s *frame, bool *key_requested, bool key_required) { // cppcheck-suppress unusedFunction
|
||||
int us_memsink_client_get(us_memsink_s *sink, us_frame_s *frame, bool *key_requested, bool key_required) {
|
||||
assert(!sink->server); // Client only
|
||||
|
||||
if (us_flock_timedwait_monotonic(sink->fd, sink->timeout) < 0) {
|
||||
@@ -190,26 +219,35 @@ int us_memsink_client_get(us_memsink_s *sink, us_frame_s *frame, bool *key_reque
|
||||
return -1;
|
||||
}
|
||||
|
||||
int retval = -2; // Not updated
|
||||
int retval = 0;
|
||||
|
||||
if (sink->mem->magic == US_MEMSINK_MAGIC) {
|
||||
if (sink->mem->version != US_MEMSINK_VERSION) {
|
||||
US_LOG_ERROR("%s-sink: Protocol version mismatch: sink=%u, required=%u",
|
||||
sink->name, sink->mem->version, US_MEMSINK_VERSION);
|
||||
retval = -1;
|
||||
goto done;
|
||||
}
|
||||
if (sink->mem->id != sink->last_id) { // When updated
|
||||
sink->last_id = sink->mem->id;
|
||||
us_frame_set_data(frame, sink->mem->data, sink->mem->used);
|
||||
US_FRAME_COPY_META(sink->mem, frame);
|
||||
*key_requested = sink->mem->key_requested;
|
||||
retval = 0;
|
||||
}
|
||||
sink->mem->last_client_ts = us_get_now_monotonic();
|
||||
if (key_required) {
|
||||
sink->mem->key_requested = true;
|
||||
}
|
||||
if (sink->mem->magic != US_MEMSINK_MAGIC) {
|
||||
retval = -2; // Not updated
|
||||
goto done;
|
||||
}
|
||||
if (sink->mem->version != US_MEMSINK_VERSION) {
|
||||
US_LOG_ERROR("%s-sink: Protocol version mismatch: sink=%u, required=%u",
|
||||
sink->name, sink->mem->version, US_MEMSINK_VERSION);
|
||||
retval = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Let the sink know that the client is alive
|
||||
sink->mem->last_client_ts = us_get_now_monotonic();
|
||||
|
||||
if (sink->mem->id == sink->last_readed_id) {
|
||||
retval = -2; // Not updated
|
||||
goto done;
|
||||
}
|
||||
|
||||
sink->last_readed_id = sink->mem->id;
|
||||
us_frame_set_data(frame, us_memsink_get_data(sink->mem), sink->mem->used);
|
||||
US_FRAME_COPY_META(sink->mem, frame);
|
||||
if (key_requested != NULL) { // We don't need it for non-H264 sinks
|
||||
*key_requested = sink->mem->key_requested;
|
||||
}
|
||||
if (key_required) {
|
||||
sink->mem->key_requested = true;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -34,6 +34,7 @@
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *obj;
|
||||
uz data_size;
|
||||
bool server;
|
||||
bool rm;
|
||||
uint client_ttl; // Only for server
|
||||
@@ -41,8 +42,11 @@ typedef struct {
|
||||
|
||||
int fd;
|
||||
us_memsink_shared_s *mem;
|
||||
u64 last_id;
|
||||
atomic_bool has_clients; // Only for server
|
||||
|
||||
u64 last_readed_id; // Only for client
|
||||
|
||||
atomic_bool has_clients; // Only for server results
|
||||
ldf unsafe_last_client_ts; // Only for server
|
||||
} us_memsink_s;
|
||||
|
||||
|
||||
|
||||
72
src/libs/memsinksh.c
Normal file
72
src/libs/memsinksh.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "memsinksh.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
us_memsink_shared_s *us_memsink_shared_map(int fd, uz data_size) {
|
||||
us_memsink_shared_s *mem = mmap(
|
||||
NULL,
|
||||
sizeof(us_memsink_shared_s) + data_size,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
fd, 0);
|
||||
if (mem == MAP_FAILED) {
|
||||
return NULL;
|
||||
}
|
||||
assert(mem != NULL);
|
||||
return mem;
|
||||
}
|
||||
|
||||
int us_memsink_shared_unmap(us_memsink_shared_s *mem, uz data_size) {
|
||||
assert(mem != NULL);
|
||||
return munmap(mem, sizeof(us_memsink_shared_s) + data_size);
|
||||
}
|
||||
|
||||
uz us_memsink_calculate_size(const char *obj) {
|
||||
const char *ptr = strrchr(obj, ':');
|
||||
if (ptr == NULL) {
|
||||
ptr = strrchr(obj, '.');
|
||||
}
|
||||
if (ptr != NULL) {
|
||||
ptr += 1;
|
||||
if (!strcasecmp(ptr, "jpeg")) {
|
||||
return 4 * 1024 * 1024;
|
||||
} else if (!strcasecmp(ptr, "h264")) {
|
||||
return 2 * 1024 * 1024;
|
||||
} else if (!strcasecmp(ptr, "raw")) {
|
||||
return 1920 * 1200 * 3; // RGB
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 *us_memsink_get_data(us_memsink_shared_s *mem) {
|
||||
return (u8*)(mem + sizeof(us_memsink_shared_s));
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -22,18 +22,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
#define US_MEMSINK_MAGIC ((u64)0xCAFEBABECAFEBABE)
|
||||
#define US_MEMSINK_VERSION ((u32)4)
|
||||
|
||||
#ifndef US_CFG_MEMSINK_MAX_DATA
|
||||
# define US_CFG_MEMSINK_MAX_DATA 33554432
|
||||
#endif
|
||||
#define US_MEMSINK_MAX_DATA ((uz)(US_CFG_MEMSINK_MAX_DATA))
|
||||
#define US_MEMSINK_VERSION ((u32)5)
|
||||
|
||||
|
||||
typedef struct {
|
||||
@@ -57,28 +50,11 @@ typedef struct {
|
||||
|
||||
ldf last_client_ts;
|
||||
bool key_requested;
|
||||
|
||||
u8 data[US_MEMSINK_MAX_DATA];
|
||||
} us_memsink_shared_s;
|
||||
|
||||
|
||||
INLINE us_memsink_shared_s *us_memsink_shared_map(int fd) {
|
||||
us_memsink_shared_s *mem = mmap(
|
||||
NULL,
|
||||
sizeof(us_memsink_shared_s),
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED,
|
||||
fd,
|
||||
0
|
||||
);
|
||||
if (mem == MAP_FAILED) {
|
||||
return NULL;
|
||||
}
|
||||
assert(mem != NULL);
|
||||
return mem;
|
||||
}
|
||||
us_memsink_shared_s *us_memsink_shared_map(int fd, uz data_size);
|
||||
int us_memsink_shared_unmap(us_memsink_shared_s *mem, uz data_size);
|
||||
|
||||
INLINE int us_memsink_shared_unmap(us_memsink_shared_s *mem) {
|
||||
assert(mem != NULL);
|
||||
return munmap(mem, sizeof(us_memsink_shared_s));
|
||||
}
|
||||
uz us_memsink_calculate_size(const char *obj);
|
||||
u8 *us_memsink_get_data(us_memsink_shared_s *mem);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -28,9 +28,9 @@
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "uslibs/types.h"
|
||||
#include "uslibs/tools.h"
|
||||
#include "uslibs/threading.h"
|
||||
#include "types.h"
|
||||
#include "tools.h"
|
||||
#include "threading.h"
|
||||
|
||||
|
||||
us_queue_s *us_queue_init(uint capacity) {
|
||||
@@ -104,9 +104,9 @@ int us_queue_get(us_queue_s *queue, void **item, ldf timeout) {
|
||||
|
||||
#undef _WAIT_OR_UNLOCK
|
||||
|
||||
int us_queue_get_free(us_queue_s *queue) {
|
||||
bool us_queue_is_empty(us_queue_s *queue) {
|
||||
US_MUTEX_LOCK(queue->mutex);
|
||||
const uint size = queue->size;
|
||||
US_MUTEX_UNLOCK(queue->mutex);
|
||||
return queue->capacity - size;
|
||||
return (bool)(queue->capacity - size);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "uslibs/types.h"
|
||||
#include "uslibs/tools.h"
|
||||
#include "types.h"
|
||||
#include "tools.h"
|
||||
|
||||
|
||||
// Based on https://github.com/seifzadeh/c-pthread-queue/blob/master/queue.h
|
||||
@@ -45,7 +45,7 @@ typedef struct {
|
||||
|
||||
#define US_QUEUE_DELETE_WITH_ITEMS(x_queue, x_free_item) { \
|
||||
if (x_queue) { \
|
||||
while (!us_queue_get_free(x_queue)) { \
|
||||
while (!us_queue_is_empty(x_queue)) { \
|
||||
void *m_ptr; \
|
||||
if (!us_queue_get(x_queue, &m_ptr, 0)) { \
|
||||
US_DELETE(m_ptr, x_free_item); \
|
||||
@@ -61,4 +61,4 @@ void us_queue_destroy(us_queue_s *queue);
|
||||
|
||||
int us_queue_put(us_queue_s *queue, void *item, ldf timeout);
|
||||
int us_queue_get(us_queue_s *queue, void **item, ldf timeout);
|
||||
int us_queue_get_free(us_queue_s *queue);
|
||||
bool us_queue_is_empty(us_queue_s *queue);
|
||||
86
src/libs/ring.c
Normal file
86
src/libs/ring.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "ring.h"
|
||||
|
||||
#include "types.h"
|
||||
#include "tools.h"
|
||||
#include "queue.h"
|
||||
|
||||
|
||||
int _acquire(us_ring_s *ring, us_queue_s *queue, ldf timeout);
|
||||
void _release(us_ring_s *ring, us_queue_s *queue, uint index);
|
||||
|
||||
|
||||
us_ring_s *us_ring_init(uint capacity) {
|
||||
us_ring_s *ring;
|
||||
US_CALLOC(ring, 1);
|
||||
US_CALLOC(ring->items, capacity);
|
||||
US_CALLOC(ring->places, capacity);
|
||||
ring->capacity = capacity;
|
||||
ring->producer = us_queue_init(capacity);
|
||||
ring->consumer = us_queue_init(capacity);
|
||||
for (uint index = 0; index < capacity; ++index) {
|
||||
ring->places[index] = index; // XXX: Just to avoid casting between pointer and uint
|
||||
assert(!us_queue_put(ring->producer, (void*)(ring->places + index), 0));
|
||||
}
|
||||
return ring;
|
||||
}
|
||||
|
||||
void us_ring_destroy(us_ring_s *ring) {
|
||||
us_queue_destroy(ring->consumer);
|
||||
us_queue_destroy(ring->producer);
|
||||
free(ring->places);
|
||||
free(ring->items);
|
||||
free(ring);
|
||||
}
|
||||
|
||||
int us_ring_producer_acquire(us_ring_s *ring, ldf timeout) {
|
||||
return _acquire(ring, ring->producer, timeout);
|
||||
}
|
||||
|
||||
void us_ring_producer_release(us_ring_s *ring, uint index) {
|
||||
_release(ring, ring->consumer, index);
|
||||
}
|
||||
|
||||
int us_ring_consumer_acquire(us_ring_s *ring, ldf timeout) {
|
||||
return _acquire(ring, ring->consumer, timeout);
|
||||
}
|
||||
|
||||
void us_ring_consumer_release(us_ring_s *ring, uint index) {
|
||||
_release(ring, ring->producer, index);
|
||||
}
|
||||
|
||||
int _acquire(us_ring_s *ring, us_queue_s *queue, ldf timeout) {
|
||||
(void)ring;
|
||||
uint *place;
|
||||
if (us_queue_get(queue, (void**)&place, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return *place;
|
||||
}
|
||||
|
||||
void _release(us_ring_s *ring, us_queue_s *queue, uint index) {
|
||||
assert(!us_queue_put(queue, (void*)(ring->places + index), 0));
|
||||
}
|
||||
63
src/libs/ring.h
Normal file
63
src/libs/ring.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "types.h"
|
||||
#include "queue.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
uz capacity;
|
||||
void **items;
|
||||
uint *places;
|
||||
us_queue_s *producer;
|
||||
us_queue_s *consumer;
|
||||
} us_ring_s;
|
||||
|
||||
|
||||
#define US_RING_INIT_WITH_ITEMS(x_ring, x_capacity, x_init_item) { \
|
||||
(x_ring) = us_ring_init(x_capacity); \
|
||||
for (uz m_index = 0; m_index < (x_ring)->capacity; ++m_index) { \
|
||||
(x_ring)->items[m_index] = x_init_item(); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define US_RING_DELETE_WITH_ITEMS(x_ring, x_destroy_item) { \
|
||||
if (x_ring) { \
|
||||
for (uz m_index = 0; m_index < (x_ring)->capacity; ++m_index) { \
|
||||
x_destroy_item((x_ring)->items[m_index]); \
|
||||
} \
|
||||
us_ring_destroy(x_ring); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
us_ring_s *us_ring_init(uint capacity);
|
||||
void us_ring_destroy(us_ring_s *ring);
|
||||
|
||||
int us_ring_producer_acquire(us_ring_s *ring, ldf timeout);
|
||||
void us_ring_producer_release(us_ring_s *ring, uint index);
|
||||
|
||||
int us_ring_consumer_acquire(us_ring_s *ring, ldf timeout);
|
||||
void us_ring_consumer_release(us_ring_s *ring, uint index);
|
||||
82
src/libs/signal.c
Normal file
82
src/libs/signal.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "signal.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32
|
||||
# define HAS_SIGABBREV_NP
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "tools.h"
|
||||
#include "logging.h"
|
||||
|
||||
|
||||
char *us_signum_to_string(int signum) {
|
||||
# ifdef HAS_SIGABBREV_NP
|
||||
const char *const name = sigabbrev_np(signum);
|
||||
# else
|
||||
const char *const name = (
|
||||
signum == SIGTERM ? "TERM" :
|
||||
signum == SIGINT ? "INT" :
|
||||
signum == SIGPIPE ? "PIPE" :
|
||||
NULL
|
||||
);
|
||||
# endif
|
||||
char *buf;
|
||||
if (name != NULL) {
|
||||
US_ASPRINTF(buf, "SIG%s", name);
|
||||
} else {
|
||||
US_ASPRINTF(buf, "SIG[%d]", signum);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void us_install_signals_handler(us_signal_handler_f handler, bool ignore_sigpipe) {
|
||||
struct sigaction sig_act = {0};
|
||||
|
||||
assert(!sigemptyset(&sig_act.sa_mask));
|
||||
sig_act.sa_handler = handler;
|
||||
assert(!sigaddset(&sig_act.sa_mask, SIGINT));
|
||||
assert(!sigaddset(&sig_act.sa_mask, SIGTERM));
|
||||
if (!ignore_sigpipe) {
|
||||
assert(!sigaddset(&sig_act.sa_mask, SIGPIPE));
|
||||
}
|
||||
|
||||
US_LOG_DEBUG("Installing SIGINT handler ...");
|
||||
assert(!sigaction(SIGINT, &sig_act, NULL));
|
||||
|
||||
US_LOG_DEBUG("Installing SIGTERM handler ...");
|
||||
assert(!sigaction(SIGTERM, &sig_act, NULL));
|
||||
|
||||
if (!ignore_sigpipe) {
|
||||
US_LOG_DEBUG("Installing SIGPIPE handler ...");
|
||||
assert(!sigaction(SIGPIPE, &sig_act, NULL));
|
||||
} else {
|
||||
US_LOG_DEBUG("Ignoring SIGPIPE ...");
|
||||
assert(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -22,13 +22,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "types.h"
|
||||
|
||||
|
||||
extern const unsigned US_BLANK_JPEG_WIDTH;
|
||||
extern const unsigned US_BLANK_JPEG_HEIGHT;
|
||||
typedef void (*us_signal_handler_f)(int);
|
||||
|
||||
extern const size_t US_BLANK_JPEG_DATA_SIZE;
|
||||
extern const uint8_t US_BLANK_JPEG_DATA[];
|
||||
|
||||
char *us_signum_to_string(int signum);
|
||||
void us_install_signals_handler(us_signal_handler_f handler, bool ignore_sigpipe);
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -28,11 +28,9 @@
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/v4l2-controls.h>
|
||||
|
||||
#include "uslibs/types.h"
|
||||
#include "uslibs/tools.h"
|
||||
#include "uslibs/xioctl.h"
|
||||
|
||||
#include "logging.h"
|
||||
#include "types.h"
|
||||
#include "tools.h"
|
||||
#include "xioctl.h"
|
||||
|
||||
|
||||
#ifndef V4L2_CID_USER_TC358743_BASE
|
||||
@@ -46,28 +44,22 @@
|
||||
#endif
|
||||
|
||||
|
||||
int us_tc358743_read_info(const char *path, us_tc358743_info_s *info) {
|
||||
US_MEMSET_ZERO(*info);
|
||||
int us_tc358743_xioctl_get_audio_hz(int fd, uint *audio_hz) {
|
||||
*audio_hz = 0;
|
||||
|
||||
int fd = -1;
|
||||
if ((fd = open(path, O_RDWR)) < 0) {
|
||||
US_JLOG_PERROR("audio", "Can't open TC358743 V4L2 device");
|
||||
struct v4l2_control ctl = {.id = TC358743_CID_AUDIO_PRESENT};
|
||||
if (us_xioctl(fd, VIDIOC_G_CTRL, &ctl) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (!ctl.value) {
|
||||
return 0; // No audio
|
||||
}
|
||||
|
||||
# define READ_CID(x_cid, x_field) { \
|
||||
struct v4l2_control m_ctl = {.id = x_cid}; \
|
||||
if (us_xioctl(fd, VIDIOC_G_CTRL, &m_ctl) < 0) { \
|
||||
US_JLOG_PERROR("audio", "Can't get value of " #x_cid); \
|
||||
close(fd); \
|
||||
return -1; \
|
||||
} \
|
||||
info->x_field = m_ctl.value; \
|
||||
}
|
||||
READ_CID(TC358743_CID_AUDIO_PRESENT, has_audio);
|
||||
READ_CID(TC358743_CID_AUDIO_SAMPLING_RATE, audio_hz);
|
||||
# undef READ_CID
|
||||
|
||||
close(fd);
|
||||
US_MEMSET_ZERO(ctl);
|
||||
ctl.id = TC358743_CID_AUDIO_SAMPLING_RATE;
|
||||
if (us_xioctl(fd, VIDIOC_G_CTRL, &ctl) < 0) {
|
||||
return -2;
|
||||
}
|
||||
*audio_hz = ctl.value;
|
||||
return 0;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -22,13 +22,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "uslibs/types.h"
|
||||
#include "types.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
bool has_audio;
|
||||
uint audio_hz;
|
||||
} us_tc358743_info_s;
|
||||
|
||||
|
||||
int us_tc358743_read_info(const char *path, us_tc358743_info_s *info);
|
||||
int us_tc358743_xioctl_get_audio_hz(int fd, uint *audio_hz);
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/syscall.h>
|
||||
@@ -56,9 +57,14 @@
|
||||
us_thread_set_name(m_new_tname_buf); \
|
||||
}
|
||||
#else
|
||||
# define US_THREAD_RENAME(_fmt, ...)
|
||||
# define US_THREAD_RENAME(x_fmt, ...)
|
||||
#endif
|
||||
|
||||
#define US_THREAD_SETTLE(x_fmt, ...) { \
|
||||
US_THREAD_RENAME((x_fmt), ##__VA_ARGS__); \
|
||||
us_thread_block_signals(); \
|
||||
}
|
||||
|
||||
#define US_MUTEX_INIT(x_mutex) assert(!pthread_mutex_init(&(x_mutex), NULL))
|
||||
#define US_MUTEX_DESTROY(x_mutex) assert(!pthread_mutex_destroy(&(x_mutex)))
|
||||
#define US_MUTEX_LOCK(x_mutex) assert(!pthread_mutex_lock(&(x_mutex)))
|
||||
@@ -78,7 +84,7 @@ INLINE void us_thread_set_name(const char *name) {
|
||||
# elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
pthread_set_name_np(pthread_self(), name);
|
||||
# elif defined(__NetBSD__)
|
||||
pthread_setname_np(pthread_self(), "%s", (void *)name);
|
||||
pthread_setname_np(pthread_self(), "%s", (void*)name);
|
||||
# else
|
||||
# error us_thread_set_name() not implemented, you can disable it using WITH_PTHREAD_NP=0
|
||||
# endif
|
||||
@@ -124,3 +130,11 @@ INLINE void us_thread_get_name(char *name) { // Always required for logging
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
INLINE void us_thread_block_signals(void) {
|
||||
sigset_t mask;
|
||||
assert(!sigemptyset(&mask));
|
||||
assert(!sigaddset(&mask, SIGINT));
|
||||
assert(!sigaddset(&mask, SIGTERM));
|
||||
assert(!pthread_sigmask(SIG_BLOCK, &mask, NULL));
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h> // Make C locale for strerror_l()
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
@@ -34,12 +35,6 @@
|
||||
|
||||
#include <sys/file.h>
|
||||
|
||||
#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32
|
||||
# define HAS_SIGABBREV_NP
|
||||
#else
|
||||
# include <signal.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
@@ -59,7 +54,7 @@
|
||||
#define US_CALLOC(x_dest, x_nmemb) assert(((x_dest) = calloc((x_nmemb), sizeof(*(x_dest)))) != NULL)
|
||||
#define US_REALLOC(x_dest, x_nmemb) assert(((x_dest) = realloc((x_dest), (x_nmemb) * sizeof(*(x_dest)))) != NULL)
|
||||
#define US_DELETE(x_dest, x_free) { if (x_dest) { x_free(x_dest); x_dest = NULL; } }
|
||||
#define US_CLOSE_FD(x_dest, x_close) { if (x_dest >= 0) { x_close(x_dest); x_dest = -1; } }
|
||||
#define US_CLOSE_FD(x_dest) { if (x_dest >= 0) { close(x_dest); x_dest = -1; } }
|
||||
#define US_MEMSET_ZERO(x_obj) memset(&(x_obj), 0, sizeof(x_obj))
|
||||
|
||||
#define US_SNPRINTF(x_dest, x_size, x_fmt, ...) assert(snprintf((x_dest), (x_size), (x_fmt), ##__VA_ARGS__) > 0)
|
||||
@@ -77,6 +72,14 @@
|
||||
(m_a > m_b ? m_a : m_b); \
|
||||
})
|
||||
|
||||
#define US_ONCE(...) { \
|
||||
const int m_reported = __LINE__; \
|
||||
if (m_reported != once) { \
|
||||
__VA_ARGS__; \
|
||||
once = m_reported; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
INLINE char *us_strdup(const char *str) {
|
||||
char *const new = strdup(str);
|
||||
@@ -181,34 +184,26 @@ INLINE int us_flock_timedwait_monotonic(int fd, ldf timeout) {
|
||||
}
|
||||
|
||||
INLINE char *us_errno_to_string(int error) {
|
||||
# if (_POSIX_C_SOURCE >= 200112L) && !defined(_GNU_SOURCE) // XSI
|
||||
char buf[2048];
|
||||
const uz max_len = sizeof(buf) - 1;
|
||||
# if (_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE
|
||||
if (strerror_r(error, buf, max_len) != 0) {
|
||||
US_SNPRINTF(buf, max_len, "Errno = %d", error);
|
||||
}
|
||||
return us_strdup(buf);
|
||||
# else
|
||||
return us_strdup(strerror_r(error, buf, max_len));
|
||||
# endif
|
||||
}
|
||||
|
||||
INLINE char *us_signum_to_string(int signum) {
|
||||
# ifdef HAS_SIGABBREV_NP
|
||||
const char *const name = sigabbrev_np(signum);
|
||||
# else
|
||||
const char *const name = (
|
||||
signum == SIGTERM ? "TERM" :
|
||||
signum == SIGINT ? "INT" :
|
||||
signum == SIGPIPE ? "PIPE" :
|
||||
NULL
|
||||
);
|
||||
# endif
|
||||
char *buf;
|
||||
if (name != NULL) {
|
||||
US_ASPRINTF(buf, "SIG%s", name);
|
||||
} else {
|
||||
US_ASPRINTF(buf, "SIG[%d]", signum);
|
||||
# elif defined(__GLIBC__) && defined(_GNU_SOURCE) // GNU
|
||||
char buf[2048];
|
||||
const uz max_len = sizeof(buf) - 1;
|
||||
return us_strdup(strerror_r(error, buf, max_len));
|
||||
|
||||
# else // BSD
|
||||
locale_t locale = newlocale(LC_MESSAGES_MASK, "C", NULL);
|
||||
if (locale) {
|
||||
char *ptr = us_strdup(strerror_l(error, locale));
|
||||
freelocale(locale);
|
||||
return ptr;
|
||||
}
|
||||
return buf;
|
||||
return us_strdup("!!! newlocale() error !!!");
|
||||
# endif
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -54,7 +54,7 @@ int us_unjpeg(const us_frame_s *src, us_frame_s *dest, bool decode) {
|
||||
|
||||
// https://stackoverflow.com/questions/19857766/error-handling-in-libjpeg
|
||||
_jpeg_error_manager_s jpeg_error;
|
||||
jpeg.err = jpeg_std_error((struct jpeg_error_mgr *)&jpeg_error);
|
||||
jpeg.err = jpeg_std_error((struct jpeg_error_mgr*)&jpeg_error);
|
||||
jpeg_error.mgr.error_exit = _jpeg_error_handler;
|
||||
jpeg_error.frame = src;
|
||||
if (setjmp(jpeg_error.jmp) < 0) {
|
||||
@@ -68,12 +68,12 @@ int us_unjpeg(const us_frame_s *src, us_frame_s *dest, bool decode) {
|
||||
|
||||
jpeg_start_decompress(&jpeg);
|
||||
|
||||
us_frame_copy_meta(src, dest);
|
||||
dest->format = V4L2_PIX_FMT_RGB24;
|
||||
dest->width = jpeg.output_width;
|
||||
dest->height = jpeg.output_height;
|
||||
dest->stride = jpeg.output_width * jpeg.output_components; // Row stride
|
||||
dest->used = 0;
|
||||
US_FRAME_COPY_META(src, dest); // cppcheck-suppress redundantAssignment
|
||||
dest->format = V4L2_PIX_FMT_RGB24; // cppcheck-suppress redundantAssignment
|
||||
dest->width = jpeg.output_width; // cppcheck-suppress redundantAssignment
|
||||
dest->height = jpeg.output_height; // cppcheck-suppress redundantAssignment
|
||||
dest->stride = jpeg.output_width * jpeg.output_components; // cppcheck-suppress redundantAssignment
|
||||
dest->used = 0; // cppcheck-suppress redundantAssignment
|
||||
|
||||
if (decode) {
|
||||
JSAMPARRAY scanlines;
|
||||
@@ -94,7 +94,7 @@ done:
|
||||
}
|
||||
|
||||
static void _jpeg_error_handler(j_common_ptr jpeg) {
|
||||
_jpeg_error_manager_s *jpeg_error = (_jpeg_error_manager_s *)jpeg->err;
|
||||
_jpeg_error_manager_s *jpeg_error = (_jpeg_error_manager_s*)jpeg->err;
|
||||
char msg[JMSG_LENGTH_MAX];
|
||||
|
||||
(*jpeg_error->mgr.format_message)(jpeg, msg);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -22,81 +22,31 @@
|
||||
|
||||
#include "blank.h"
|
||||
|
||||
#include "../libs/types.h"
|
||||
#include "../libs/tools.h"
|
||||
#include "../libs/frame.h"
|
||||
#include "../libs/frametext.h"
|
||||
|
||||
static us_frame_s *_init_internal(void);
|
||||
static us_frame_s *_init_external(const char *path);
|
||||
#include "encoders/cpu/encoder.h"
|
||||
|
||||
|
||||
us_frame_s *us_blank_frame_init(const char *path) {
|
||||
us_frame_s *blank = NULL;
|
||||
|
||||
if (path && path[0] != '\0') {
|
||||
blank = _init_external(path);
|
||||
}
|
||||
|
||||
if (blank != NULL) {
|
||||
US_LOG_INFO("Using external blank placeholder: %s", path);
|
||||
} else {
|
||||
blank = _init_internal();
|
||||
US_LOG_INFO("Using internal blank placeholder");
|
||||
}
|
||||
us_blank_s *us_blank_init(void) {
|
||||
us_blank_s *blank;
|
||||
US_CALLOC(blank, 1);
|
||||
blank->ft = us_frametext_init();
|
||||
blank->raw = blank->ft->frame;
|
||||
blank->jpeg = us_frame_init();
|
||||
us_blank_draw(blank, "< NO SIGNAL >", 640, 480);
|
||||
return blank;
|
||||
}
|
||||
|
||||
static us_frame_s *_init_internal(void) {
|
||||
us_frame_s *const blank = us_frame_init();
|
||||
us_frame_set_data(blank, US_BLANK_JPEG_DATA, US_BLANK_JPEG_DATA_SIZE);
|
||||
blank->width = US_BLANK_JPEG_WIDTH;
|
||||
blank->height = US_BLANK_JPEG_HEIGHT;
|
||||
blank->format = V4L2_PIX_FMT_JPEG;
|
||||
return blank;
|
||||
void us_blank_draw(us_blank_s *blank, const char *text, uint width, uint height) {
|
||||
us_frametext_draw(blank->ft, text, width, height);
|
||||
us_cpu_encoder_compress(blank->raw, blank->jpeg, 95);
|
||||
}
|
||||
|
||||
static us_frame_s *_init_external(const char *path) {
|
||||
FILE *fp = NULL;
|
||||
|
||||
us_frame_s *blank = us_frame_init();
|
||||
blank->format = V4L2_PIX_FMT_JPEG;
|
||||
|
||||
if ((fp = fopen(path, "rb")) == NULL) {
|
||||
US_LOG_PERROR("Can't open blank placeholder '%s'", path);
|
||||
goto error;
|
||||
}
|
||||
|
||||
const size_t chunk_size = 100 * 1024;
|
||||
while (true) {
|
||||
if (blank->used + chunk_size >= blank->allocated) {
|
||||
us_frame_realloc_data(blank, blank->used + chunk_size * 2);
|
||||
}
|
||||
|
||||
const size_t readed = fread(blank->data + blank->used, 1, chunk_size, fp);
|
||||
blank->used += readed;
|
||||
|
||||
if (readed < chunk_size) {
|
||||
if (feof(fp)) {
|
||||
break;
|
||||
} else {
|
||||
US_LOG_PERROR("Can't read blank placeholder");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
us_frame_s *const decoded = us_frame_init();
|
||||
if (us_unjpeg(blank, decoded, false) < 0) {
|
||||
us_frame_destroy(decoded);
|
||||
goto error;
|
||||
}
|
||||
blank->width = decoded->width;
|
||||
blank->height = decoded->height;
|
||||
us_frame_destroy(decoded);
|
||||
|
||||
goto ok;
|
||||
|
||||
error:
|
||||
US_DELETE(blank, us_frame_destroy);
|
||||
|
||||
ok:
|
||||
US_DELETE(fp, fclose);
|
||||
return blank;
|
||||
void us_blank_destroy(us_blank_s *blank) {
|
||||
us_frame_destroy(blank->jpeg);
|
||||
us_frametext_destroy(blank->ft);
|
||||
free(blank);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -22,17 +22,19 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#include "../libs/tools.h"
|
||||
#include "../libs/logging.h"
|
||||
#include "../libs/types.h"
|
||||
#include "../libs/frame.h"
|
||||
#include "../libs/unjpeg.h"
|
||||
|
||||
#include "data/blank_jpeg.h"
|
||||
#include "../libs/frametext.h"
|
||||
|
||||
|
||||
us_frame_s *us_blank_frame_init(const char *path);
|
||||
typedef struct {
|
||||
us_frametext_s *ft;
|
||||
us_frame_s *raw;
|
||||
us_frame_s *jpeg;
|
||||
} us_blank_s;
|
||||
|
||||
|
||||
us_blank_s *us_blank_init(void);
|
||||
void us_blank_destroy(us_blank_s *blank);
|
||||
|
||||
void us_blank_draw(us_blank_s *blank, const char *text, uint width, uint height);
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB |
@@ -1,723 +0,0 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
*****************************************************************************/
|
||||
|
||||
#include "blank_jpeg.h"
|
||||
|
||||
|
||||
const unsigned US_BLANK_JPEG_WIDTH = 640;
|
||||
const unsigned US_BLANK_JPEG_HEIGHT = 480;
|
||||
|
||||
const size_t US_BLANK_JPEG_DATA_SIZE = 13845;
|
||||
const uint8_t US_BLANK_JPEG_DATA[] = {
|
||||
0xFF, 0xD8, 0xFF, 0xE1, 0x09, 0x50, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x6E, 0x73, 0x2E, 0x61, 0x64, 0x6F, 0x62,
|
||||
0x65, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x78, 0x61, 0x70, 0x2F, 0x31, 0x2E, 0x30, 0x2F, 0x00, 0x3C, 0x3F, 0x78, 0x70, 0x61,
|
||||
0x63, 0x6B, 0x65, 0x74, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x3D, 0x22, 0xEF, 0xBB, 0xBF, 0x22, 0x20, 0x69, 0x64, 0x3D,
|
||||
0x22, 0x57, 0x35, 0x4D, 0x30, 0x4D, 0x70, 0x43, 0x65, 0x68, 0x69, 0x48, 0x7A, 0x72, 0x65, 0x53, 0x7A, 0x4E, 0x54, 0x63,
|
||||
0x7A, 0x6B, 0x63, 0x39, 0x64, 0x22, 0x3F, 0x3E, 0x20, 0x3C, 0x78, 0x3A, 0x78, 0x6D, 0x70, 0x6D, 0x65, 0x74, 0x61, 0x20,
|
||||
0x78, 0x6D, 0x6C, 0x6E, 0x73, 0x3A, 0x78, 0x3D, 0x22, 0x61, 0x64, 0x6F, 0x62, 0x65, 0x3A, 0x6E, 0x73, 0x3A, 0x6D, 0x65,
|
||||
0x74, 0x61, 0x2F, 0x22, 0x20, 0x78, 0x3A, 0x78, 0x6D, 0x70, 0x74, 0x6B, 0x3D, 0x22, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x20,
|
||||
0x58, 0x4D, 0x50, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x35, 0x2E, 0x36, 0x2D, 0x63, 0x31, 0x33, 0x38, 0x20, 0x37, 0x39,
|
||||
0x2E, 0x31, 0x35, 0x39, 0x38, 0x32, 0x34, 0x2C, 0x20, 0x32, 0x30, 0x31, 0x36, 0x2F, 0x30, 0x39, 0x2F, 0x31, 0x34, 0x2D,
|
||||
0x30, 0x31, 0x3A, 0x30, 0x39, 0x3A, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x3E, 0x20, 0x3C,
|
||||
0x72, 0x64, 0x66, 0x3A, 0x52, 0x44, 0x46, 0x20, 0x78, 0x6D, 0x6C, 0x6E, 0x73, 0x3A, 0x72, 0x64, 0x66, 0x3D, 0x22, 0x68,
|
||||
0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x33, 0x2E, 0x6F, 0x72, 0x67, 0x2F, 0x31, 0x39, 0x39,
|
||||
0x39, 0x2F, 0x30, 0x32, 0x2F, 0x32, 0x32, 0x2D, 0x72, 0x64, 0x66, 0x2D, 0x73, 0x79, 0x6E, 0x74, 0x61, 0x78, 0x2D, 0x6E,
|
||||
0x73, 0x23, 0x22, 0x3E, 0x20, 0x3C, 0x72, 0x64, 0x66, 0x3A, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F,
|
||||
0x6E, 0x20, 0x72, 0x64, 0x66, 0x3A, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x3D, 0x22, 0x22, 0x2F, 0x3E, 0x20, 0x3C, 0x2F, 0x72,
|
||||
0x64, 0x66, 0x3A, 0x52, 0x44, 0x46, 0x3E, 0x20, 0x3C, 0x2F, 0x78, 0x3A, 0x78, 0x6D, 0x70, 0x6D, 0x65, 0x74, 0x61, 0x3E,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x3F, 0x78, 0x70, 0x61, 0x63, 0x6B, 0x65, 0x74, 0x20, 0x65,
|
||||
0x6E, 0x64, 0x3D, 0x22, 0x77, 0x22, 0x3F, 0x3E, 0xFF, 0xED, 0x00, 0x2C, 0x50, 0x68, 0x6F, 0x74, 0x6F, 0x73, 0x68, 0x6F,
|
||||
0x70, 0x20, 0x33, 0x2E, 0x30, 0x00, 0x38, 0x42, 0x49, 0x4D, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xD4, 0x1D,
|
||||
0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E, 0xFF, 0xDB, 0x00, 0x84, 0x00, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x50, 0xFF, 0xEE, 0x00, 0x0E, 0x41, 0x64,
|
||||
0x6F, 0x62, 0x65, 0x00, 0x64, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x01, 0xE0, 0x02, 0x80, 0x03,
|
||||
0x00, 0x11, 0x00, 0x01, 0x11, 0x01, 0x02, 0x11, 0x01, 0xFF, 0xC4, 0x00, 0x7D, 0x00, 0x01, 0x00, 0x02, 0x03, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x07, 0x08, 0x09, 0x05, 0x06, 0x02, 0x03,
|
||||
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
|
||||
0x01, 0x00, 0x01, 0x04, 0x02, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08, 0x04, 0x06, 0x03, 0x00, 0x00, 0x00, 0x03, 0x02, 0x04,
|
||||
0x05, 0x06, 0x01, 0x07, 0x08, 0x09, 0x11, 0x12, 0x0A, 0x13, 0x14, 0x21, 0x22, 0x15, 0x37, 0x77, 0xB6, 0x16, 0x23, 0x31,
|
||||
0x35, 0x39, 0x41, 0x75, 0xB4, 0x17, 0x38, 0xB5, 0xB7, 0x18, 0x1A, 0x24, 0x32, 0x51, 0x78, 0x56, 0x97, 0xD4, 0x11, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xDA, 0x00, 0x0C,
|
||||
0x03, 0x00, 0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD1, 0xAF, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
0xFF, 0xD2, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x07, 0xFF, 0xD3, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD4, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD5, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD6, 0xAF, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
0xFF, 0xD7, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD1, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD2, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD3, 0xAF, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
0xFF, 0xD4, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x07, 0xFF, 0xD5, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD6, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD7, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, 0xAF, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
0xFF, 0xD1, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x07, 0xFF, 0xD2, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD3, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD4, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD5, 0xAF, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
0xFF, 0xD6, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x07, 0xFF, 0xD7, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD1, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD2, 0xAF, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
0xFF, 0xD3, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x06, 0x4C, 0xE9, 0x5B, 0x0B, 0x1C, 0xAF, 0x71, 0xF5, 0x2E, 0x2F, 0x29, 0x65, 0x69, 0x92, 0xC6, 0x64, 0xBB, 0x33,
|
||||
0x43, 0xB0, 0xC8, 0xE3, 0xAF, 0xED, 0xA1, 0xBC, 0xB1, 0xBF, 0xB1, 0xBC, 0xDA, 0x71, 0x56, 0xF7, 0x76, 0x57, 0xB6, 0x97,
|
||||
0x14, 0x49, 0x6F, 0x75, 0x69, 0x75, 0x6F, 0x25, 0x54, 0x49, 0x1D, 0x74, 0xD5, 0x45, 0x74, 0x55, 0xCD, 0x35, 0x71, 0xCF,
|
||||
0x1C, 0xF3, 0xC0, 0x24, 0x45, 0xEB, 0x5F, 0xE9, 0x19, 0x61, 0xD4, 0x3F, 0xB6, 0x7C, 0xBB, 0xF1, 0x67, 0x4E, 0xB6, 0xC6,
|
||||
0x75, 0x4C, 0x95, 0x47, 0x71, 0xDC, 0x5D, 0x53, 0xAA, 0xE3, 0x20, 0xB3, 0xC6, 0x75, 0x94, 0xF5, 0x71, 0x15, 0xBF, 0xF4,
|
||||
0xE7, 0x4D, 0xC2, 0x63, 0xA0, 0x8A, 0x1B, 0x1D, 0x02, 0xF6, 0x5F, 0x6E, 0x72, 0x56, 0x50, 0x51, 0xF6, 0xF0, 0xD3, 0xD7,
|
||||
0xF7, 0xE2, 0xA6, 0x9B, 0x0A, 0xEB, 0xA2, 0xC4, 0x23, 0x22, 0x0D, 0xD8, 0xF4, 0xE3, 0xEB, 0xED, 0x2F, 0xB5, 0xBC, 0xE3,
|
||||
0xF1, 0xA7, 0xAE, 0xBB, 0x17, 0x5C, 0xC7, 0x6D, 0xBA, 0x46, 0xDD, 0xD9, 0x36, 0x38, 0x7D, 0x97, 0x5B, 0xCB, 0x47, 0x5C,
|
||||
0xB8, 0xDC, 0xC6, 0x36, 0x6B, 0x0C, 0x85, 0x72, 0x59, 0xDD, 0xD1, 0x1C, 0x91, 0x49, 0xCC, 0x55, 0x57, 0x1D, 0x3C, 0xFE,
|
||||
0x9A, 0xA9, 0xE7, 0x8E, 0x78, 0xE3, 0x9E, 0x39, 0x06, 0xF5, 0xFA, 0xF4, 0x78, 0xE9, 0xD2, 0x3E, 0x34, 0xF9, 0x4D, 0xD5,
|
||||
0x7A, 0x6F, 0x44, 0x75, 0xBE, 0xBB, 0xD6, 0x3A, 0xBE, 0x6B, 0xA0, 0x30, 0xBB, 0x3E, 0x57, 0x0B, 0xAD, 0x45, 0x73, 0x0D,
|
||||
0x95, 0xEE, 0x7E, 0xE3, 0xB1, 0x7B, 0x23, 0x15, 0x36, 0x52, 0x6A, 0x6E, 0xAE, 0x6E, 0x6B, 0xE6, 0xEA, 0x4C, 0x76, 0x26,
|
||||
0xDA, 0x2E, 0x79, 0xE2, 0xAE, 0x38, 0xF8, 0x43, 0x4F, 0xE5, 0xFF, 0x00, 0xC8, 0x6B, 0xE7, 0xA6, 0xFF, 0x00, 0xA5, 0xD7,
|
||||
0x6F, 0xFA, 0x83, 0xED, 0x57, 0xD7, 0xF8, 0xEB, 0xFE, 0x3A, 0xE7, 0xA3, 0xB5, 0x1C, 0x8C, 0x56, 0x3B, 0xCF, 0x6B, 0x64,
|
||||
0x71, 0xF5, 0xE4, 0x3E, 0x59, 0x0A, 0xA0, 0xA6, 0xEB, 0x8D, 0x57, 0x49, 0xC4, 0x73, 0x35, 0xA5, 0x1B, 0x1E, 0xD3, 0x25,
|
||||
0xBC, 0x91, 0xD7, 0x3F, 0xCA, 0x68, 0x6D, 0x31, 0xD6, 0xF2, 0xD3, 0x2C, 0xF5, 0xF3, 0x5D, 0x76, 0xF6, 0xF7, 0x01, 0xDA,
|
||||
0xEE, 0xC7, 0x83, 0xD0, 0x8F, 0xD3, 0x07, 0x27, 0xFF, 0x00, 0x0E, 0x76, 0x0E, 0xA9, 0xAF, 0xCA, 0xCE, 0xF4, 0xD7, 0x61,
|
||||
0xAE, 0xD3, 0x69, 0xC6, 0x65, 0x31, 0x98, 0xCE, 0xEE, 0xCB, 0x58, 0xE5, 0xE1, 0xB3, 0xBE, 0xB0, 0xA6, 0x1D, 0xEA, 0xDF,
|
||||
0x71, 0xC9, 0xE0, 0xBA, 0x47, 0x57, 0xBF, 0xAA, 0x6B, 0xA9, 0x7F, 0x11, 0x8F, 0xB1, 0xB2, 0xFD, 0xA3, 0x67, 0x55, 0x31,
|
||||
0xCD, 0x2D, 0x9F, 0xDC, 0x8E, 0xD6, 0xAE, 0x43, 0x15, 0xEA, 0xFE, 0xA3, 0x9E, 0x87, 0x9D, 0xD5, 0x2D, 0x3A, 0x2F, 0x73,
|
||||
0xFA, 0x79, 0xEB, 0x1D, 0x25, 0x84, 0xCA, 0xDF, 0x5B, 0xC1, 0x46, 0xE7, 0xAB, 0x74, 0xDF, 0x5C, 0x5B, 0x59, 0x63, 0x20,
|
||||
0xB8, 0xB7, 0xBB, 0xB4, 0xBA, 0xBE, 0xCD, 0xEC, 0x5D, 0x39, 0xCE, 0xAD, 0xD9, 0xD8, 0xCB, 0x7B, 0x5A, 0x2E, 0x7E, 0x54,
|
||||
0xD1, 0x8C, 0xB4, 0xC8, 0xD7, 0x55, 0x5E, 0xD2, 0xF1, 0x4D, 0x32, 0x45, 0x1F, 0x20, 0xF1, 0xFC, 0xCA, 0xF4, 0x2E, 0xEB,
|
||||
0xAD, 0xBF, 0xAB, 0x6B, 0xF2, 0x77, 0xD3, 0x43, 0x7A, 0xA7, 0xB2, 0xB4, 0x6B, 0xDC, 0x3D, 0xCE, 0xD3, 0x1F, 0x52, 0xF1,
|
||||
0xB2, 0x45, 0xBA, 0xC1, 0x9C, 0xC2, 0x5A, 0xD1, 0x27, 0x37, 0x55, 0x75, 0x06, 0xEB, 0x45, 0x73, 0x64, 0x32, 0xB9, 0x1B,
|
||||
0x0F, 0xC3, 0x57, 0x4D, 0x78, 0x3C, 0xBC, 0xB7, 0x59, 0x09, 0xAE, 0x28, 0x96, 0x28, 0xEE, 0xF9, 0xB9, 0xA6, 0x3B, 0x2A,
|
||||
0xC2, 0x30, 0x12, 0x47, 0x24, 0x52, 0x57, 0x14, 0xB4, 0x57, 0x14, 0xB1, 0x57, 0x54, 0x72, 0x47, 0x25, 0x3C, 0xD1, 0x24,
|
||||
0x72, 0x51, 0xCF, 0x34, 0xD7, 0x45, 0x74, 0x55, 0xC7, 0x15, 0x51, 0x5D, 0x15, 0x71, 0xCF, 0x1C, 0xF1, 0xCF, 0x1E, 0xFC,
|
||||
0x72, 0x0F, 0xC0, 0x3A, 0x19, 0xE9, 0xA3, 0xE0, 0x76, 0x6B, 0xD4, 0x03, 0xC8, 0x9B, 0x6E, 0xAE, 0xE7, 0x33, 0x79, 0xAA,
|
||||
0x75, 0xDE, 0xAB, 0x85, 0x97, 0x75, 0xED, 0x5D, 0xBB, 0x1F, 0x14, 0x32, 0x64, 0xF1, 0x7A, 0xAD, 0xB5, 0xF5, 0x9E, 0x3A,
|
||||
0x1C, 0x56, 0xBD, 0xC5, 0xE4, 0x17, 0x18, 0xFA, 0xB6, 0x8D, 0x8F, 0x25, 0x7D, 0x1D, 0xBD, 0xA7, 0xDF, 0xA2, 0xB8, 0xE0,
|
||||
0x8B, 0x89, 0xEE, 0xAA, 0x8E, 0x6A, 0x6D, 0xEA, 0x86, 0xB0, 0x90, 0x37, 0x92, 0x7D, 0xB9, 0xE8, 0xB9, 0xE9, 0x95, 0x9B,
|
||||
0x8F, 0xC7, 0x5B, 0x0F, 0x0C, 0x74, 0x8F, 0x21, 0x3B, 0x3F, 0x09, 0x69, 0x8C, 0x9F, 0x70, 0xB4, 0xCB, 0xE9, 0x1A, 0x5F,
|
||||
0x67, 0xDF, 0xEB, 0x52, 0x5E, 0x5B, 0x71, 0x91, 0x86, 0x9D, 0xC3, 0xB1, 0x7B, 0x82, 0xBC, 0xFD, 0xF5, 0xAE, 0xC9, 0x95,
|
||||
0xB5, 0xC8, 0x53, 0x77, 0xC6, 0x3B, 0x19, 0x0C, 0x90, 0x43, 0x0C, 0x94, 0x53, 0x5D, 0x36, 0x91, 0xD3, 0x6F, 0x10, 0x3F,
|
||||
0x5B, 0x0F, 0x40, 0xFA, 0x35, 0xFA, 0x99, 0x78, 0xCF, 0xDA, 0x3D, 0xD7, 0xD2, 0xB0, 0x6A, 0x9E, 0x21, 0x6D, 0x5D, 0x51,
|
||||
0x87, 0x97, 0x2B, 0xB9, 0x6C, 0x18, 0xDD, 0x73, 0x0F, 0xD6, 0x37, 0xBD, 0x51, 0x27, 0x18, 0xDA, 0xB8, 0xC4, 0xCB, 0xD8,
|
||||
0xFD, 0x51, 0xAF, 0xE4, 0xB9, 0xEB, 0xFD, 0x9B, 0x4F, 0xCE, 0xF3, 0x8E, 0xA7, 0xED, 0x5C, 0x62, 0x6A, 0xAA, 0x6B, 0xDB,
|
||||
0x88, 0xE5, 0x86, 0xD6, 0xFA, 0x3B, 0xDE, 0x6E, 0xA1, 0xE4, 0x38, 0x81, 0xE8, 0xDF, 0xD6, 0xDD, 0x77, 0xD8, 0xFE, 0xA4,
|
||||
0x7D, 0x35, 0xD7, 0xDD, 0x89, 0xAA, 0xE8, 0xFD, 0xB3, 0xA1, 0xDE, 0xDB, 0x77, 0x0C, 0x77, 0xD8, 0x3D, 0xC3, 0x56, 0xB1,
|
||||
0xDA, 0x74, 0xDD, 0x8E, 0x8C, 0x3F, 0x53, 0xEF, 0x97, 0xD8, 0x9C, 0x8C, 0xDA, 0xDE, 0xE1, 0x88, 0xAE, 0x1B, 0x88, 0x63,
|
||||
0xBE, 0xB2, 0x86, 0xF2, 0xD7, 0x8B, 0xBB, 0x3A, 0x27, 0x86, 0x5A, 0x28, 0xAF, 0x9A, 0x23, 0x96, 0x9F, 0x6A, 0x43, 0xEB,
|
||||
0xFD, 0x72, 0xFA, 0xCB, 0xAD, 0xFA, 0x93, 0xCF, 0x7D, 0x8F, 0x4E, 0xEA, 0x9E, 0xBE, 0xD2, 0x3A, 0xCB, 0x51, 0x83, 0xAC,
|
||||
0xFA, 0xDA, 0xFE, 0x0D, 0x5B, 0xAF, 0x75, 0x3C, 0x0E, 0x97, 0xAE, 0x43, 0x7D, 0x7D, 0x8B, 0xBA, 0x92, 0xFA, 0xF6, 0x2C,
|
||||
0x1E, 0xB9, 0x61, 0x8D, 0xC6, 0x47, 0x77, 0x79, 0x25, 0x3C, 0x55, 0x2C, 0x9C, 0x45, 0xC5, 0x72, 0x73, 0xC7, 0xBD, 0x5C,
|
||||
0xF3, 0xC8, 0x35, 0xA7, 0xC0, 0x5F, 0x4F, 0xEE, 0xE3, 0xF5, 0x01, 0xED, 0x59, 0xF4, 0x3E, 0xBA, 0xAE, 0xDB, 0x58, 0xD3,
|
||||
0xF5, 0x98, 0x6D, 0x32, 0x5D, 0x99, 0xDA, 0x59, 0xAB, 0x39, 0xEF, 0x35, 0xED, 0x17, 0x11, 0x7B, 0x24, 0xD4, 0x59, 0x51,
|
||||
0xC5, 0x94, 0x13, 0x5A, 0xCD, 0x9F, 0xD9, 0xF3, 0x55, 0x5B, 0x4B, 0x46, 0x3B, 0x17, 0x14, 0xD0, 0xD7, 0x73, 0x54, 0x52,
|
||||
0x57, 0x24, 0xB0, 0x5B, 0x45, 0x3D, 0xC4, 0x41, 0x22, 0xCE, 0xC0, 0xEA, 0x0F, 0x43, 0xCF, 0x4A, 0x3B, 0x4C, 0x56, 0xA9,
|
||||
0xDC, 0xDA, 0x87, 0xFE, 0x24, 0x7B, 0xD2, 0x28, 0xAC, 0xEF, 0xF2, 0x9A, 0xEE, 0xC5, 0x8C, 0xB0, 0xEE, 0x6E, 0xC0, 0xB8,
|
||||
0x8E, 0x4B, 0x39, 0x66, 0x8A, 0xEF, 0x33, 0xA2, 0xE5, 0x32, 0x1A, 0xFF, 0x00, 0x4C, 0xE8, 0xF8, 0xA9, 0x69, 0xBC, 0xF9,
|
||||
0xDA, 0xDA, 0xE4, 0x28, 0xB3, 0xBC, 0xBB, 0x86, 0x68, 0xA4, 0xF7, 0xBC, 0xA6, 0x1F, 0xBF, 0x18, 0x60, 0xAD, 0x2F, 0xD4,
|
||||
0xD7, 0xD1, 0x2F, 0xB3, 0xAF, 0xE6, 0xD3, 0x3B, 0x67, 0xD3, 0x9F, 0x48, 0xE9, 0xDD, 0x77, 0x31, 0x73, 0x61, 0x04, 0x7B,
|
||||
0xB6, 0x1B, 0xA1, 0x7A, 0x7F, 0x23, 0x6F, 0x8C, 0x8A, 0x2B, 0x9A, 0xAE, 0xE6, 0xBC, 0xCC, 0xE4, 0x3A, 0xDA, 0xC7, 0x0B,
|
||||
0xD8, 0x98, 0x4B, 0x68, 0x6B, 0xB5, 0x86, 0x9E, 0x78, 0xC3, 0xDB, 0xE4, 0xA6, 0xB9, 0xA2, 0x49, 0x22, 0x92, 0x8E, 0x22,
|
||||
0xF9, 0x71, 0x20, 0x63, 0x8F, 0x52, 0xDF, 0x4B, 0xCF, 0x07, 0x35, 0x5F, 0x19, 0x24, 0xF3, 0x77, 0xC3, 0x5E, 0xEE, 0xD6,
|
||||
0x35, 0x8D, 0x06, 0xE3, 0x9C, 0x75, 0x38, 0x9D, 0x16, 0xF7, 0x74, 0x9F, 0x75, 0xD1, 0xBB, 0x0A, 0xEA, 0xFE, 0xEA, 0x58,
|
||||
0xEB, 0xC2, 0x75, 0xB6, 0xC7, 0x7D, 0x79, 0x95, 0xDB, 0x71, 0xDB, 0xD5, 0xAD, 0x31, 0xCF, 0x54, 0xD8, 0x8B, 0xD9, 0x6F,
|
||||
0x78, 0xA7, 0x9B, 0x49, 0x63, 0x93, 0xF0, 0x1C, 0xC1, 0x2F, 0x20, 0xC1, 0x3E, 0x85, 0x7E, 0x2D, 0x74, 0x8F, 0x97, 0x1B,
|
||||
0x57, 0x96, 0x9D, 0x59, 0xDD, 0xFA, 0x46, 0x1B, 0x6A, 0xC3, 0xE4, 0x3A, 0x53, 0x0B, 0x6F, 0x84, 0xCD, 0x4F, 0x8E, 0xC7,
|
||||
0x49, 0xB5, 0xE8, 0x99, 0x6C, 0x86, 0xCF, 0x55, 0xBD, 0x1B, 0x4E, 0x85, 0x9F, 0xBB, 0xB3, 0xBA, 0xBB, 0xD6, 0x76, 0x4B,
|
||||
0x2A, 0xA9, 0xA2, 0xAA, 0x67, 0x83, 0xF4, 0x4D, 0x4D, 0x1F, 0x66, 0xE2, 0x89, 0xAD, 0xEB, 0x92, 0x1A, 0xC3, 0x9D, 0x3E,
|
||||
0x77, 0x78, 0x45, 0xDA, 0x3E, 0x07, 0xF7, 0x96, 0x5B, 0xA9, 0xBB, 0x02, 0x19, 0x72, 0x9A, 0xFD, 0xF7, 0x17, 0x19, 0xAE,
|
||||
0xB2, 0xEC, 0x2B, 0x7B, 0x4A, 0xE0, 0xC2, 0x76, 0x0E, 0x9D, 0xCD, 0xCD, 0x51, 0x5B, 0x64, 0xED, 0x3F, 0x54, 0xB1, 0xD9,
|
||||
0x66, 0xF1, 0xD5, 0x73, 0x4C, 0x19, 0x4C, 0x7D, 0x55, 0xD5, 0x2D, 0x95, 0xD7, 0xF9, 0xD7, 0x04, 0xB6, 0xF3, 0xCC, 0x1A,
|
||||
0x5A, 0x09, 0x44, 0xFA, 0x03, 0xF8, 0x73, 0xE3, 0x0F, 0x93, 0x7D, 0x45, 0xE4, 0x06, 0x6F, 0xBE, 0xFA, 0x5F, 0x4D, 0xED,
|
||||
0x0C, 0xB6, 0xAF, 0xD8, 0xFA, 0xC6, 0x2B, 0x5F, 0xBF, 0xD9, 0xAD, 0xAF, 0x26, 0xB8, 0xC5, 0xE3, 0xAF, 0x75, 0x89, 0x6E,
|
||||
0xEE, 0xAD, 0x2D, 0xAB, 0xB5, 0xBC, 0xB5, 0xF6, 0x86, 0x6B, 0x9A, 0x38, 0xAF, 0x9E, 0x2A, 0xE2, 0xAF, 0xD5, 0xFD, 0x9E,
|
||||
0xDE, 0xFC, 0xFB, 0x84, 0x62, 0x33, 0x10, 0xC7, 0x6F, 0x97, 0xCA, 0xC1, 0x0D, 0x1C, 0x47, 0x0C, 0x19, 0x2B, 0xE8, 0x62,
|
||||
0x8E, 0x9F, 0x7F, 0x6A, 0x23, 0x8E, 0xE6, 0x5A, 0x23, 0xA3, 0x8F, 0x7F, 0x7E, 0x7D, 0xA9, 0xA6, 0x9E, 0x38, 0x07, 0x9A,
|
||||
0x09, 0x48, 0xFA, 0x14, 0x7A, 0x66, 0xF5, 0x9F, 0x79, 0xF4, 0xF7, 0x72, 0x79, 0x05, 0xE4, 0x87, 0x5E, 0x61, 0x77, 0x3D,
|
||||
0x47, 0xB2, 0xB1, 0x99, 0xDE, 0x9B, 0xEA, 0x5C, 0x5E, 0xC9, 0x88, 0xB0, 0xC8, 0xFE, 0x03, 0x1B, 0x17, 0xCE, 0xDB, 0x7E,
|
||||
0xEC, 0xDD, 0x66, 0x4C, 0x84, 0x17, 0xB1, 0xE2, 0x76, 0x5B, 0x4C, 0xD5, 0x11, 0x63, 0x30, 0xD9, 0x6B, 0x7A, 0x62, 0xBF,
|
||||
0xC6, 0x5D, 0x63, 0xEF, 0xF9, 0x8A, 0xBA, 0x7E, 0xE7, 0x1C, 0x82, 0x3D, 0xDE, 0x53, 0x78, 0xF1, 0xB9, 0x78, 0xA7, 0xDF,
|
||||
0xFD, 0x9F, 0xD0, 0x7B, 0xD4, 0x33, 0x7E, 0xD8, 0xEB, 0xDD, 0x9A, 0xF7, 0x17, 0x67, 0x93, 0x92, 0xD6, 0x4B, 0x4B, 0x7D,
|
||||
0x9B, 0x5B, 0x96, 0xAF, 0xC5, 0xEA, 0xDB, 0x6E, 0x3A, 0x29, 0x3D, 0xF9, 0xE3, 0x1D, 0xB3, 0xE0, 0x27, 0xB7, 0xBD, 0x8B,
|
||||
0x8F, 0x7E, 0x79, 0x8F, 0x89, 0xBE, 0xDD, 0x5E, 0xD5, 0xD1, 0x57, 0x1C, 0x06, 0xBF, 0x82, 0x57, 0x7F, 0x4E, 0xFF, 0x00,
|
||||
0x8E, 0x9E, 0x3E, 0x77, 0x67, 0x4E, 0x79, 0x17, 0x94, 0xEE, 0x5E, 0x8A, 0xE9, 0xBE, 0xDB, 0xC9, 0xE1, 0x3B, 0x33, 0x54,
|
||||
0xB0, 0xC2, 0xE4, 0x7B, 0x3B, 0xAC, 0x74, 0x9D, 0xF6, 0xFB, 0x11, 0x63, 0x71, 0xAB, 0x4F, 0x71, 0x71, 0x65, 0x8B, 0xBB,
|
||||
0xDA, 0xB0, 0x79, 0x6B, 0x8C, 0x7D, 0xA4, 0xF7, 0x1C, 0x71, 0x5D, 0x71, 0xC5, 0x55, 0x14, 0x55, 0x5F, 0x1F, 0x2E, 0x78,
|
||||
0xE7, 0x9F, 0xCC, 0x11, 0x57, 0xCD, 0xC7, 0x1C, 0x59, 0x9C, 0xBC, 0x51, 0x51, 0x44, 0x51, 0x45, 0x93, 0xBF, 0x8E, 0x38,
|
||||
0xE3, 0xA7, 0x8A, 0x23, 0x8E, 0x3A, 0x2E, 0xA5, 0xA6, 0x8A, 0x28, 0xA2, 0x9E, 0x38, 0xA6, 0x8A, 0x28, 0xA7, 0x8E, 0x38,
|
||||
0xE3, 0x8E, 0x38, 0xF6, 0xE3, 0x80, 0x79, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD4, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x57, 0xE8, 0x6F, 0xDF, 0x97, 0x4C, 0xFF, 0x00, 0x15, 0xFA, 0xEF, 0xF9,
|
||||
0xBF, 0x0E, 0x0B, 0x0F, 0x7C, 0xC4, 0xF3, 0x8B, 0xAA, 0x7C, 0x4D, 0xED, 0x0F, 0x1B, 0x7A, 0xDB, 0xBC, 0xEC, 0x31, 0x90,
|
||||
0x75, 0x47, 0x93, 0x95, 0xF6, 0x96, 0x95, 0x9E, 0xDD, 0x33, 0x1F, 0x66, 0x6C, 0x26, 0x9F, 0x96, 0xC1, 0x45, 0xA0, 0xC1,
|
||||
0x84, 0xE7, 0x6D, 0xB2, 0xBB, 0xA2, 0x4B, 0x09, 0x34, 0x5D, 0x82, 0x3D, 0xBE, 0xEA, 0xD3, 0x29, 0x3C, 0xDC, 0x73, 0x1D,
|
||||
0x9F, 0x15, 0x45, 0x34, 0xBE, 0xD6, 0xB4, 0xDC, 0x55, 0x48, 0x45, 0x0F, 0xD6, 0x3B, 0xD2, 0xB2, 0xEF, 0xC3, 0xFD, 0xBA,
|
||||
0x6E, 0xFE, 0xE8, 0xEC, 0x54, 0xF9, 0x2F, 0x17, 0x7B, 0x0B, 0x33, 0xF2, 0x92, 0xCA, 0xC2, 0x9A, 0xEE, 0xFF, 0x00, 0xE0,
|
||||
0xBE, 0xD1, 0x99, 0x9A, 0xB9, 0xAD, 0xB5, 0x8B, 0xE9, 0x69, 0xAA, 0x5A, 0xEB, 0xD1, 0x33, 0x32, 0x57, 0xED, 0x83, 0xC8,
|
||||
0x57, 0xCF, 0x34, 0xC3, 0x5F, 0x3C, 0x58, 0x5C, 0x55, 0xC4, 0xDF, 0x84, 0x96, 0xF4, 0x34, 0xC3, 0xD2, 0x8B, 0xFC, 0x46,
|
||||
0x3C, 0x46, 0xFE, 0x2D, 0xE3, 0x3F, 0xE9, 0xD9, 0x30, 0x74, 0xFF, 0x00, 0xEA, 0x34, 0xD7, 0x72, 0x9B, 0x7F, 0x9E, 0x1E,
|
||||
0x3B, 0x6A, 0x78, 0x48, 0xA8, 0xB8, 0xCD, 0x6D, 0x1E, 0x3F, 0xE9, 0x3A, 0xEE, 0x22, 0x09, 0x24, 0xA6, 0x18, 0xE6, 0xCA,
|
||||
0x66, 0xBB, 0x93, 0xB4, 0x71, 0xB8, 0xF8, 0xAB, 0x96, 0xAF, 0xD3, 0x15, 0x12, 0x5D, 0xDC, 0xD1, 0xC7, 0x35, 0x73, 0xF9,
|
||||
0x53, 0xC7, 0x3E, 0xE0, 0xEA, 0xF7, 0xA8, 0x47, 0x67, 0xD9, 0xFA, 0x4A, 0xFA, 0x63, 0xF5, 0xFF, 0x00, 0x49, 0x78, 0xF7,
|
||||
0x3C, 0x78, 0x1D, 0xEB, 0x3D, 0x06, 0x2F, 0xA5, 0xB4, 0xCD, 0xA2, 0xCE, 0xDE, 0x2B, 0x7C, 0x95, 0xAE, 0x46, 0xFB, 0x15,
|
||||
0x7F, 0x9E, 0xED, 0x4E, 0xD8, 0xAE, 0x88, 0xFE, 0xD7, 0x1C, 0x6C, 0xB9, 0x4A, 0xA1, 0xBB, 0x96, 0x39, 0xE9, 0xE7, 0xE5,
|
||||
0x6B, 0x95, 0xCB, 0x43, 0x35, 0x34, 0xF3, 0x44, 0x3F, 0x00, 0x41, 0x76, 0x69, 0xA6, 0xB9, 0x9A, 0x5B, 0x8B, 0x89, 0x64,
|
||||
0x9E, 0xE2, 0x79, 0x2B, 0x9A, 0x79, 0xE6, 0xAE, 0xB9, 0x66, 0x9A, 0x69, 0x6B, 0xE6, 0xB9, 0x65, 0x96, 0x5A, 0xF9, 0xAA,
|
||||
0xB9, 0x24, 0x92, 0xBA, 0xB9, 0xE6, 0xAA, 0xB9, 0xE7, 0x9E, 0x79, 0xE7, 0x9F, 0x7E, 0x41, 0xFC, 0xC1, 0xDF, 0xBF, 0x40,
|
||||
0x9F, 0x36, 0x76, 0xBE, 0x97, 0xF2, 0x73, 0x13, 0xE3, 0x0E, 0xC5, 0x99, 0xBC, 0xBC, 0xE9, 0xDF, 0x21, 0x6E, 0xAE, 0xB1,
|
||||
0xD8, 0xEC, 0x3D, 0xD4, 0xF2, 0x4D, 0x65, 0xA9, 0x76, 0xBD, 0xAE, 0x36, 0x7B, 0xBD, 0x73, 0x3F, 0x88, 0x8A, 0x49, 0x79,
|
||||
0xA2, 0xC3, 0x8D, 0xAE, 0x3B, 0x1E, 0x71, 0x17, 0xF1, 0xC3, 0x47, 0x1F, 0x8B, 0x96, 0x6B, 0x29, 0x24, 0xE7, 0xDA, 0xD6,
|
||||
0x90, 0x7C, 0x6F, 0xAF, 0xBF, 0x8B, 0x9A, 0xF7, 0x40, 0x79, 0x9F, 0x47, 0x60, 0x69, 0x58, 0xEB, 0x6C, 0x4E, 0xA9, 0xE4,
|
||||
0x7E, 0xB3, 0x37, 0x65, 0xDD, 0xE3, 0x2D, 0x22, 0xAE, 0x1B, 0x5B, 0x2E, 0xC5, 0xB5, 0xCB, 0x5C, 0xE2, 0xFB, 0x0E, 0xAB,
|
||||
0x68, 0xFE, 0x1C, 0xC5, 0xF6, 0xF3, 0x97, 0x75, 0x5A, 0x66, 0x26, 0xE7, 0x8A, 0xF9, 0xE7, 0x9B, 0xDC, 0x9C, 0xFC, 0x7C,
|
||||
0x28, 0xA3, 0x88, 0xF8, 0xA8, 0x38, 0x6C, 0x09, 0x2C, 0x7D, 0x34, 0x7D, 0x9B, 0xA8, 0x6B, 0x9E, 0x41, 0xF7, 0xF7, 0x58,
|
||||
0x66, 0xB2, 0x56, 0x76, 0x1B, 0x5F, 0x66, 0xF5, 0xBE, 0xB5, 0x95, 0xD2, 0xED, 0xEE, 0xE6, 0xA2, 0x09, 0x33, 0x55, 0x75,
|
||||
0xF6, 0x5F, 0x31, 0x75, 0xB0, 0xE2, 0x71, 0xBC, 0x49, 0x4F, 0x1F, 0x8B, 0xC9, 0x51, 0x8B, 0xD8, 0xF8, 0xBE, 0xFB, 0x14,
|
||||
0x55, 0xF7, 0x39, 0xB4, 0xB2, 0x9E, 0x5E, 0x29, 0xAA, 0x88, 0x64, 0xAA, 0x80, 0xD3, 0x5F, 0x58, 0x8F, 0x07, 0x7C, 0x87,
|
||||
0xE8, 0xCF, 0x2B, 0xBB, 0xCB, 0xBB, 0x36, 0x2D, 0x4F, 0x66, 0xDA, 0x7A, 0x67, 0xB8, 0xBB, 0x2F, 0x69, 0xEC, 0x6D, 0x5F,
|
||||
0xB5, 0xF1, 0x76, 0x17, 0xB9, 0x8D, 0x67, 0x19, 0x1E, 0xE9, 0x97, 0xB9, 0xCE, 0x53, 0xA5, 0x6C, 0xF9, 0x3B, 0x68, 0xA6,
|
||||
0x8B, 0x54, 0xCB, 0xEB, 0x72, 0xDE, 0x57, 0x61, 0x69, 0x6F, 0x7D, 0xCC, 0x1C, 0x5E, 0x5A, 0x5A, 0x53, 0x25, 0xAF, 0x32,
|
||||
0x51, 0x4D, 0x7F, 0x6C, 0x38, 0xE2, 0x0E, 0xBD, 0x7A, 0x12, 0xFF, 0x00, 0x89, 0xEF, 0x8F, 0xBF, 0xE9, 0x3D, 0xCB, 0xFF,
|
||||
0x00, 0x64, 0xFB, 0x04, 0x19, 0x07, 0xEA, 0x0D, 0xFF, 0x00, 0x11, 0xAD, 0xA3, 0xF8, 0x51, 0xD5, 0x9F, 0xF4, 0x8B, 0xC0,
|
||||
0x77, 0x77, 0x44, 0xBF, 0xC6, 0x7A, 0x47, 0xFA, 0x2E, 0xE3, 0xBB, 0x13, 0x5D, 0xC2, 0xD9, 0xC3, 0xDC, 0x7B, 0x2E, 0x83,
|
||||
0xAE, 0x6E, 0x57, 0x12, 0x5D, 0x58, 0x5B, 0xCD, 0x71, 0x91, 0xEF, 0x7E, 0xF1, 0x87, 0x17, 0x4E, 0x1E, 0x4D, 0x82, 0x2E,
|
||||
0x7D, 0xAD, 0xF2, 0x36, 0x9D, 0x69, 0x8F, 0xC9, 0x5B, 0xC3, 0x24, 0x55, 0x57, 0xC5, 0x17, 0x16, 0x18, 0x1E, 0x63, 0xA7,
|
||||
0x9E, 0x6B, 0x97, 0xDE, 0xA0, 0x84, 0x2E, 0xD1, 0xB4, 0x6C, 0x9B, 0xBE, 0xC9, 0x9D, 0xDC, 0x37, 0x0C, 0xEE, 0x57, 0x67,
|
||||
0xDA, 0xB6, 0x7C, 0xAD, 0xF6, 0x73, 0x61, 0xD8, 0x73, 0x97, 0xD7, 0x19, 0x2C, 0xC6, 0x6B, 0x31, 0x92, 0xB8, 0x92, 0xEA,
|
||||
0xFF, 0x00, 0x25, 0x92, 0xBF, 0xBA, 0x92, 0x5B, 0x8B, 0xBB, 0xCB, 0xBB, 0x89, 0x6A, 0xAE, 0xBA, 0xEB, 0xAB, 0x9A, 0xAA,
|
||||
0xAB, 0x90, 0x78, 0x20, 0xF4, 0x79, 0xCC, 0x65, 0xAA, 0xC4, 0xC7, 0x80, 0xAB, 0x29, 0x91, 0xAB, 0x05, 0x16, 0x46, 0x6C,
|
||||
0xC4, 0x58, 0x5E, 0x6F, 0x6E, 0x79, 0xC4, 0xC7, 0x96, 0xB8, 0xB6, 0x82, 0xCA, 0x7C, 0xA4, 0x78, 0xEE, 0x65, 0xFC, 0x1D,
|
||||
0x19, 0x19, 0xEC, 0xED, 0xA3, 0x8A, 0xB9, 0xF8, 0xA3, 0x89, 0x6A, 0x8A, 0x3A, 0x69, 0xE6, 0xAE, 0x69, 0xA7, 0x8E, 0x38,
|
||||
0x09, 0x2E, 0x7D, 0x32, 0x7F, 0xBF, 0x7F, 0x26, 0xFF, 0x00, 0x84, 0x9A, 0x9F, 0xF3, 0x8D, 0x40, 0xEB, 0x6E, 0xED, 0xB1,
|
||||
0xF8, 0xBF, 0xEA, 0xF5, 0x8F, 0xF2, 0xB7, 0xC1, 0xAE, 0xCD, 0x82, 0xCB, 0x47, 0xEF, 0xBF, 0x1B, 0xBB, 0x6B, 0xB2, 0xF0,
|
||||
0x1A, 0x96, 0x46, 0x3A, 0x60, 0xBC, 0xD8, 0xF0, 0xF6, 0x7A, 0x96, 0xDF, 0x93, 0xD6, 0x75, 0x5E, 0xE0, 0xD1, 0x3F, 0x15,
|
||||
0x25, 0xBC, 0xD9, 0x7C, 0x3D, 0xD5, 0xBD, 0xBD, 0xBD, 0x86, 0xD1, 0x8B, 0xE2, 0x4A, 0x69, 0xE2, 0x49, 0x7E, 0x15, 0xF3,
|
||||
0x0D, 0x37, 0x16, 0x17, 0x14, 0x84, 0x28, 0x7C, 0x99, 0xF1, 0xAF, 0xB5, 0x7C, 0x4A, 0xEE, 0x5D, 0xBB, 0xA3, 0xBB, 0x8B,
|
||||
0x07, 0x56, 0x1B, 0x6D, 0xD5, 0x6E, 0xB8, 0xE6, 0x0B, 0xBB, 0x7F, 0xBB, 0x36, 0x0B, 0x69, 0xC0, 0x5D, 0x55, 0x25, 0x58,
|
||||
0x5D, 0xBF, 0x55, 0xC8, 0xC9, 0x14, 0x3C, 0x65, 0x35, 0xCC, 0xED, 0xB4, 0x7C, 0xD7, 0x04, 0xBF, 0x1A, 0x24, 0x8A, 0x4A,
|
||||
0x64, 0xB7, 0x9E, 0x88, 0x6E, 0x61, 0x9A, 0x18, 0xC2, 0x54, 0x7F, 0x4C, 0x97, 0xEE, 0x37, 0xC9, 0xEF, 0xE2, 0xBE, 0x9D,
|
||||
0xFC, 0xA1, 0x70, 0x08, 0x7B, 0x67, 0xFF, 0x00, 0xBF, 0x73, 0x5F, 0xEA, 0xD9, 0x1F, 0xF7, 0x93, 0x03, 0x28, 0xF8, 0xED,
|
||||
0xD1, 0x9B, 0x97, 0x92, 0xDD, 0xDF, 0xD6, 0x5D, 0x13, 0xA0, 0xC1, 0xCC, 0xBB, 0x47, 0x65, 0xED, 0x78, 0xDD, 0x72, 0xD2,
|
||||
0xE3, 0x98, 0x6A, 0xB8, 0xB7, 0xC3, 0xD8, 0xCF, 0x5F, 0x33, 0xE7, 0x36, 0x4C, 0x84, 0x54, 0x57, 0x1D, 0x75, 0x62, 0xB5,
|
||||
0x8C, 0x1D, 0xBD, 0xCE, 0x42, 0xEF, 0xE3, 0x57, 0x15, 0x7E, 0x1A, 0xDA, 0xBF, 0x8F, 0xBD, 0x5E, 0xDC, 0x72, 0x12, 0xE5,
|
||||
0xF5, 0x32, 0xF3, 0xA6, 0xC7, 0xD2, 0xDB, 0x59, 0xF0, 0xCB, 0xC4, 0xDF, 0x18, 0x78, 0x86, 0xDE, 0xEB, 0xAF, 0x26, 0xD1,
|
||||
0xB7, 0x2D, 0xDF, 0x09, 0xC4, 0xF1, 0xF1, 0x3D, 0xFF, 0x00, 0x4C, 0x68, 0xD7, 0x3F, 0xB2, 0xE0, 0xD3, 0xF3, 0xF7, 0x54,
|
||||
0x53, 0x54, 0x94, 0xDF, 0xF7, 0x16, 0x56, 0xDA, 0xFE, 0x6C, 0x85, 0xDF, 0x14, 0xF1, 0x71, 0xFF, 0x00, 0xA4, 0x92, 0x5E,
|
||||
0x7F, 0x3B, 0x9E, 0x2A, 0xE4, 0x30, 0xE7, 0xAF, 0x17, 0x8F, 0x9A, 0x8F, 0x92, 0xFE, 0x35, 0xF4, 0xAF, 0xA8, 0xFF, 0x00,
|
||||
0x47, 0x51, 0x46, 0x77, 0x1F, 0x8C, 0xD5, 0x75, 0x8B, 0x4D, 0xC7, 0x23, 0x65, 0x6F, 0x4F, 0x17, 0x39, 0x7E, 0xA0, 0xDF,
|
||||
0x2B, 0x8B, 0x23, 0xA5, 0x67, 0xF2, 0x50, 0xC3, 0xF7, 0x6B, 0x82, 0xFB, 0x49, 0xDA, 0x33, 0x35, 0x59, 0x5D, 0xC5, 0x57,
|
||||
0x3C, 0xCB, 0x07, 0x19, 0x6A, 0xE9, 0x97, 0x9A, 0x78, 0xB4, 0xE7, 0x8A, 0x42, 0x22, 0xC0, 0x98, 0xFF, 0x00, 0xD3, 0x25,
|
||||
0xFB, 0x8D, 0xF2, 0x7B, 0xF8, 0xAF, 0xA7, 0x7F, 0x28, 0x5C, 0x02, 0x1E, 0xD9, 0xFF, 0x00, 0xEF, 0xDC, 0xD7, 0xFA, 0xB6,
|
||||
0x47, 0xFD, 0xE4, 0xC0, 0xF2, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0xFF, 0xD5, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x57, 0xE8, 0x6F, 0xDF, 0x97, 0x4C, 0xFF, 0x00, 0x15, 0xFA, 0xEF, 0xF9, 0xBF, 0x0E,
|
||||
0x09, 0x43, 0xFD, 0x4F, 0xFF, 0x00, 0xDC, 0x5E, 0x17, 0x7F, 0xAB, 0x77, 0xF7, 0xFB, 0x3E, 0x9D, 0x06, 0x35, 0xF4, 0x75,
|
||||
0xF5, 0x2C, 0xD3, 0xFB, 0x1B, 0x50, 0x87, 0xD3, 0x8F, 0xCD, 0x6A, 0xF1, 0x7B, 0x76, 0x89, 0xBA, 0x62, 0x64, 0xD0, 0xFA,
|
||||
0x83, 0x66, 0xDE, 0x64, 0xA6, 0xF3, 0x17, 0x90, 0xC5, 0x5F, 0xDB, 0xD1, 0x63, 0x6B, 0xD2, 0x7B, 0x75, 0xCD, 0xE5, 0x5C,
|
||||
0x7C, 0x6D, 0xA4, 0xA3, 0x8E, 0x28, 0xD6, 0x6F, 0x2B, 0x92, 0x99, 0x20, 0x9B, 0x8A, 0x2C, 0x28, 0xAE, 0x9E, 0x78, 0xB0,
|
||||
0xA6, 0x80, 0xF8, 0x7C, 0x7F, 0xA6, 0xA6, 0xE3, 0xE0, 0x17, 0xAB, 0x8F, 0x89, 0x17, 0x78, 0x58, 0xF2, 0x5B, 0x27, 0x8E,
|
||||
0x9D, 0x85, 0xDE, 0x11, 0x4B, 0xD5, 0x1B, 0xC4, 0xD4, 0x57, 0x71, 0x3E, 0x2A, 0x4E, 0x71, 0x99, 0x7B, 0xD9, 0x3A, 0xE7,
|
||||
0x72, 0xB9, 0xA2, 0x2A, 0x61, 0x83, 0x6D, 0xC1, 0xDA, 0xD3, 0x5F, 0xD8, 0x9B, 0xF4, 0xC7, 0x98, 0xB1, 0x8B, 0xF1, 0x51,
|
||||
0x53, 0x4C, 0x94, 0x5D, 0x5B, 0xDA, 0x87, 0xD9, 0x7A, 0xE9, 0x6C, 0xB8, 0x9D, 0x2F, 0xD5, 0x33, 0xC2, 0x3D, 0xC7, 0x3D,
|
||||
0x2C, 0x30, 0x60, 0xF5, 0x3D, 0x17, 0xA4, 0xB6, 0x5C, 0xCC, 0xF7, 0x32, 0xC7, 0x05, 0xBC, 0x38, 0x9C, 0x17, 0x91, 0x5B,
|
||||
0xEE, 0x53, 0x23, 0x2C, 0xF3, 0x4D, 0xFD, 0x4C, 0x30, 0xC7, 0x67, 0x6B, 0x5F, 0x35, 0x55, 0x5F, 0xE9, 0xA6, 0x9E, 0x39,
|
||||
0xE7, 0x9F, 0xC8, 0x1B, 0x0F, 0xF5, 0x36, 0x68, 0xF9, 0xCC, 0xB7, 0x4D, 0xF8, 0xB7, 0xD9, 0x56, 0x34, 0x49, 0x36, 0xB5,
|
||||
0xA8, 0x76, 0x26, 0xFF, 0x00, 0xA9, 0xE6, 0x64, 0x86, 0x3A, 0xE5, 0x86, 0x2C, 0x87, 0x60, 0x6B, 0x9A, 0xFE, 0x57, 0x01,
|
||||
0x71, 0x34, 0xB4, 0x55, 0xCC, 0x71, 0x45, 0x54, 0x3D, 0x7F, 0x7B, 0x45, 0x35, 0x55, 0xC7, 0xB5, 0x55, 0x49, 0xC7, 0x1C,
|
||||
0x55, 0xC7, 0x3C, 0xFB, 0x54, 0x10, 0xEA, 0x00, 0x1B, 0xDD, 0xE9, 0x87, 0xA2, 0xE7, 0xFB, 0x0F, 0xD4, 0x1B, 0xC4, 0x1C,
|
||||
0x1E, 0xB9, 0x1C, 0xF2, 0x5E, 0xE2, 0xFB, 0xDB, 0x41, 0xDE, 0xAF, 0x79, 0x82, 0x89, 0xAB, 0xE6, 0x2C, 0x07, 0x5A, 0x66,
|
||||
0xAD, 0xFB, 0x0B, 0x66, 0x92, 0x5E, 0x60, 0xA6, 0xAA, 0xA8, 0x83, 0xFA, 0x3F, 0xAC, 0x5C, 0xF1, 0x5D, 0x55, 0x7B, 0x51,
|
||||
0xED, 0x57, 0xEA, 0xE7, 0x8E, 0x39, 0xE4, 0x1D, 0x98, 0xFA, 0x9C, 0xF6, 0x9C, 0x35, 0xDF, 0x6B, 0x78, 0xA1, 0xA4, 0xC1,
|
||||
0x24, 0x1C, 0xEC, 0x1A, 0xFF, 0x00, 0x5E, 0xF6, 0x56, 0xD3, 0x93, 0x86, 0x9F, 0x87, 0xE2, 0x68, 0xC3, 0x6E, 0x3B, 0x26,
|
||||
0xB5, 0x89, 0xC1, 0x49, 0x2F, 0xB7, 0x3F, 0x73, 0xEC, 0x4B, 0x7B, 0xA3, 0x64, 0x78, 0x8F, 0xDF, 0x8E, 0x29, 0xF9, 0x51,
|
||||
0x5F, 0xB7, 0xBF, 0x3E, 0xFE, 0xC1, 0x17, 0x90, 0x7D, 0x36, 0x9B, 0xB9, 0xED, 0xBD, 0x77, 0xB5, 0x60, 0x37, 0x9D, 0x13,
|
||||
0x64, 0xCC, 0xEA, 0x1B, 0x8E, 0xAD, 0x93, 0xB6, 0xCC, 0xEB, 0x9B, 0x36, 0xBD, 0x90, 0xB9, 0xC5, 0x66, 0xB0, 0xB9, 0x4B,
|
||||
0x3A, 0xFE, 0xE5, 0xBD, 0xF6, 0x3F, 0x21, 0x67, 0x24, 0x57, 0x16, 0xD3, 0xC7, 0x57, 0xE5, 0xEF, 0x4D, 0x5F, 0xAA, 0x9E,
|
||||
0x79, 0xA7, 0x9F, 0x7E, 0x39, 0xE7, 0x8E, 0x42, 0x45, 0x7E, 0x34, 0x7D, 0x47, 0xDD, 0xDF, 0xA7, 0xD9, 0xE3, 0xF5, 0x4F,
|
||||
0x2A, 0x3A, 0xA7, 0x59, 0xEF, 0x0C, 0x04, 0x76, 0x3F, 0xB3, 0x6F, 0x77, 0x5D, 0x42, 0xBB, 0x7D, 0x0F, 0xB0, 0x2E, 0x69,
|
||||
0xAA, 0x9A, 0x29, 0x92, 0xFF, 0x00, 0x3B, 0x87, 0xAA, 0xDA, 0xFB, 0x43, 0xD9, 0xA4, 0x96, 0x1E, 0x2B, 0x8A, 0xBB, 0x7B,
|
||||
0x6B, 0x5C, 0x0D, 0x15, 0xFC, 0xF8, 0xAF, 0x99, 0x39, 0xE6, 0x9E, 0x69, 0x90, 0x3A, 0x21, 0xB8, 0xF8, 0x41, 0xE9, 0xB5,
|
||||
0xEA, 0xFD, 0xD0, 0x9B, 0x17, 0x75, 0x78, 0x85, 0x8E, 0xD7, 0xBA, 0x77, 0xB8, 0x21, 0xAE, 0xFA, 0x9A, 0xB2, 0xFA, 0xCE,
|
||||
0xBB, 0x69, 0xA3, 0x5D, 0xE1, 0xB7, 0xD9, 0xED, 0xE8, 0xC9, 0x73, 0xAD, 0xF7, 0x77, 0x59, 0xE1, 0xB9, 0xAF, 0x09, 0x77,
|
||||
0x1E, 0x6E, 0x4E, 0x79, 0xAA, 0x4C, 0xB5, 0x8D, 0x32, 0x4F, 0x2D, 0x72, 0x57, 0x73, 0x6F, 0x7B, 0x77, 0x4D, 0x12, 0xC3,
|
||||
0x28, 0x70, 0xFB, 0xD1, 0x67, 0x50, 0xD8, 0x7A, 0xF7, 0xD5, 0xBB, 0xAA, 0x74, 0x1D, 0xBB, 0x1D, 0x26, 0x23, 0x6B, 0xD1,
|
||||
0xEF, 0xFC, 0x82, 0xD4, 0x36, 0x7C, 0x4C, 0xD5, 0x51, 0x5C, 0xD8, 0xBD, 0x87, 0x5A, 0xEA, 0x8E, 0xCB, 0xC2, 0xE6, 0xB1,
|
||||
0xD2, 0xD7, 0x1D, 0x55, 0xC7, 0x54, 0x96, 0x59, 0x2B, 0x29, 0x62, 0xAB, 0x9A, 0x79, 0xE6, 0x9E, 0x79, 0xA7, 0xF2, 0xE7,
|
||||
0x9E, 0x01, 0xED, 0xFD, 0x41, 0xBF, 0xE2, 0x35, 0xB4, 0x7F, 0x0A, 0x3A, 0xB3, 0xFE, 0x91, 0x78, 0x0E, 0xDB, 0xFA, 0xD6,
|
||||
0x63, 0x2E, 0x3B, 0x67, 0xD2, 0x2B, 0xAA, 0xBB, 0x13, 0x47, 0x8F, 0x8B, 0x9D, 0x5B, 0x05, 0x9A, 0xF1, 0xDF, 0xB5, 0xAF,
|
||||
0x2B, 0xB1, 0xF6, 0x9E, 0xDA, 0x8D, 0x2F, 0x62, 0xD2, 0x72, 0x5A, 0xBE, 0x2E, 0xE6, 0x3A, 0xED, 0x7D, 0xA1, 0xAA, 0xCE,
|
||||
0x9C, 0x96, 0xFF, 0x00, 0x8E, 0xE7, 0x8A, 0xF8, 0xE3, 0xED, 0xFC, 0x79, 0xE3, 0x9E, 0x3D, 0xB8, 0xF6, 0xE7, 0x80, 0x84,
|
||||
0x68, 0x24, 0x81, 0xA0, 0xFD, 0x47, 0xFD, 0xDF, 0xA0, 0xE8, 0x9A, 0x56, 0x89, 0x67, 0xE3, 0x7F, 0x55, 0x64, 0x2D, 0x34,
|
||||
0xAD, 0x4B, 0x5C, 0xD4, 0xAD, 0x6F, 0xEE, 0x76, 0x9D, 0xBA, 0x2B, 0x9B, 0xDB, 0x6D, 0x73, 0x0F, 0x67, 0x87, 0x82, 0xEE,
|
||||
0xE2, 0x38, 0xA9, 0xFB, 0x51, 0xCD, 0x73, 0x15, 0x9F, 0x15, 0xD7, 0x4D, 0x3F, 0xA7, 0x8A, 0xAA, 0xE7, 0x8E, 0x3F, 0x20,
|
||||
0x77, 0xBB, 0xC6, 0x5F, 0x30, 0xF6, 0x5F, 0x39, 0xBD, 0x36, 0xBB, 0x9B, 0xBE, 0xB6, 0xCD, 0x3B, 0x07, 0xA2, 0xE6, 0x2F,
|
||||
0xF4, 0xBE, 0xFF, 0x00, 0xD5, 0xEB, 0xC0, 0xEB, 0xB7, 0xD7, 0xF9, 0x1C, 0x6D, 0x10, 0x6B, 0x7A, 0x8E, 0x4E, 0x08, 0x2E,
|
||||
0xA8, 0xB9, 0xC9, 0x71, 0xC5, 0xD7, 0x32, 0xDC, 0xD3, 0x3F, 0x3C, 0xD7, 0x4F, 0x3F, 0xA7, 0x8E, 0x78, 0xFC, 0x81, 0xC3,
|
||||
0xEF, 0xA6, 0x4F, 0xF7, 0xEF, 0xE4, 0xDF, 0xF0, 0x93, 0x53, 0xFE, 0x71, 0xA8, 0x1C, 0xA7, 0xF2, 0xB3, 0xB8, 0xBB, 0x1B,
|
||||
0xA0, 0x3D, 0x50, 0x7C, 0x9C, 0xED, 0xFE, 0xA6, 0xD9, 0xAF, 0xB5, 0x0D, 0xFF, 0x00, 0x47, 0xF2, 0xC7, 0xBA, 0x72, 0xD8,
|
||||
0x1C, 0xD5, 0x85, 0x7F, 0x9D, 0x12, 0x71, 0xD8, 0x3B, 0x1C, 0x17, 0x76, 0x17, 0xD6, 0xF5, 0x7B, 0xC1, 0x91, 0xC3, 0xE5,
|
||||
0xAC, 0x66, 0x96, 0xD6, 0xF6, 0xD2, 0x6A, 0x6B, 0x82, 0xEE, 0xD6, 0x69, 0x22, 0x92, 0x9A, 0xA8, 0xAF, 0x9E, 0x39, 0x09,
|
||||
0x24, 0x66, 0xF1, 0xBE, 0x3F, 0xFD, 0x40, 0x3E, 0x16, 0xF1, 0x9C, 0xC1, 0x51, 0xAF, 0x75, 0xAF, 0x98, 0x7D, 0x3D, 0x67,
|
||||
0xF6, 0x68, 0x86, 0x79, 0x2A, 0x92, 0xE7, 0x47, 0xDC, 0x2E, 0x20, 0xAA, 0x7A, 0xB0, 0x79, 0x39, 0x78, 0xA2, 0x5C, 0xC6,
|
||||
0x5B, 0xA5, 0x3B, 0x32, 0xAB, 0x4A, 0xEA, 0xB4, 0xB9, 0xE2, 0x99, 0xA4, 0xC7, 0xDC, 0xD1, 0xCD, 0x7C, 0x71, 0x2D, 0xCD,
|
||||
0x95, 0xCD, 0xBC, 0xE1, 0xFE, 0x7D, 0x3C, 0x5D, 0x61, 0xBE, 0x74, 0xBE, 0x9F, 0xE6, 0x67, 0x55, 0xF6, 0x76, 0xB5, 0x91,
|
||||
0xD4, 0x37, 0xDD, 0x1B, 0xBC, 0x35, 0x7C, 0x0E, 0xCD, 0xAF, 0x65, 0x22, 0xFB, 0x77, 0x56, 0x17, 0xF6, 0xDA, 0x84, 0xB5,
|
||||
0xD3, 0x55, 0x15, 0xD3, 0xCD, 0x50, 0xDD, 0xD8, 0xDE, 0xDB, 0x49, 0x1D, 0xC5, 0xAD, 0xCC, 0x35, 0x57, 0x6F, 0x77, 0x6B,
|
||||
0x2C, 0x73, 0x43, 0x5D, 0x71, 0x49, 0x45, 0x75, 0x04, 0x2E, 0x73, 0xFF, 0x00, 0xDF, 0xB9, 0xAF, 0xF5, 0x6C, 0x8F, 0xFB,
|
||||
0xC9, 0x81, 0x2A, 0xDF, 0x40, 0x5F, 0x1C, 0x75, 0x4E, 0x94, 0xE9, 0xEE, 0xEB, 0xF5, 0x22, 0xEE, 0xEE, 0x6D, 0xF0, 0x1A,
|
||||
0xE6, 0x3F, 0x5A, 0xDA, 0xB5, 0xDE, 0xBF, 0xCC, 0x65, 0x21, 0xE7, 0xED, 0xE2, 0x3A, 0xFB, 0x4E, 0xA2, 0xBC, 0x9F, 0x6A,
|
||||
0x6F, 0x36, 0x74, 0x55, 0x4D, 0x7F, 0x7E, 0xBC, 0xA6, 0x53, 0x13, 0x46, 0x1E, 0xCE, 0xA8, 0x7E, 0x37, 0x3C, 0x55, 0x8E,
|
||||
0xBE, 0x83, 0x8E, 0x2A, 0xA6, 0xE7, 0x8E, 0x2A, 0x0F, 0xE9, 0xDE, 0x1E, 0x5E, 0x7D, 0x3E, 0xBE, 0x48, 0xF6, 0x66, 0xC3,
|
||||
0xDC, 0x3D, 0xD9, 0xD6, 0x5D, 0xCF, 0xBD, 0xF6, 0x36, 0xD3, 0xC6, 0x3A, 0x9C, 0xDE, 0xC5, 0x77, 0x77, 0xE4, 0x16, 0x27,
|
||||
0xF1, 0x11, 0x62, 0x31, 0x96, 0x98, 0x7C, 0x6D, 0xB5, 0xAE, 0x23, 0x5E, 0xED, 0xBC, 0x46, 0x0B, 0x15, 0x67, 0x67, 0x8E,
|
||||
0xB1, 0x8A, 0x3A, 0x21, 0xB4, 0xB5, 0x82, 0x2E, 0x3E, 0x3C, 0xD5, 0xF1, 0xF9, 0xD5, 0x55, 0x55, 0x07, 0x4A, 0x3C, 0x1C,
|
||||
0xF2, 0x83, 0xD3, 0x33, 0xC9, 0xDE, 0xB9, 0xD9, 0xBC, 0x01, 0xF1, 0xA6, 0xCF, 0x6D, 0xB4, 0xEB, 0xD8, 0xBA, 0xC7, 0x76,
|
||||
0xA6, 0x4E, 0xB1, 0xEC, 0x28, 0xF7, 0x69, 0xA9, 0xBB, 0xD1, 0x76, 0x5C, 0x8C, 0x96, 0x9B, 0x7D, 0x96, 0xBB, 0xB0, 0x76,
|
||||
0x06, 0xC7, 0xB5, 0x66, 0x2E, 0xE4, 0xB5, 0xBD, 0xDA, 0xF9, 0x9E, 0x8B, 0x5E, 0x2E, 0xF9, 0xAE, 0xD2, 0x89, 0x39, 0x96,
|
||||
0xDE, 0x8A, 0x63, 0x86, 0xAE, 0x63, 0x08, 0x4F, 0xF9, 0x71, 0xE3, 0x7E, 0xD9, 0xE2, 0x57, 0x91, 0x3D, 0xA5, 0xD0, 0x5B,
|
||||
0x85, 0x17, 0x12, 0x5E, 0x68, 0x5B, 0x2D, 0xD5, 0xA6, 0x1B, 0x2F, 0x34, 0x15, 0x41, 0x1E, 0xCF, 0xA8, 0xDE, 0xFB, 0x64,
|
||||
0x35, 0x1D, 0xAA, 0xD7, 0x8E, 0x69, 0xA6, 0x3E, 0x60, 0xCF, 0xEB, 0xD7, 0x36, 0xF7, 0x15, 0x53, 0x47, 0x35, 0x71, 0x0C,
|
||||
0xD5, 0x57, 0x17, 0x3C, 0xFC, 0xE3, 0xAB, 0x8E, 0x02, 0x52, 0x1F, 0x4C, 0x97, 0xEE, 0x37, 0xC9, 0xEF, 0xE2, 0xBE, 0x9D,
|
||||
0xFC, 0xA1, 0x70, 0x08, 0x7B, 0x67, 0xFF, 0x00, 0xBF, 0x73, 0x5F, 0xEA, 0xD9, 0x1F, 0xF7, 0x93, 0x03, 0xC9, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD6, 0xAF,
|
||||
0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x57,
|
||||
0xE8, 0x6F, 0xDF, 0x97, 0x4C, 0xFF, 0x00, 0x15, 0xFA, 0xEF, 0xF9, 0xBF, 0x0E, 0x09, 0x43, 0xFD, 0x4F, 0xFF, 0x00, 0xDC,
|
||||
0x5E, 0x17, 0x7F, 0xAB, 0x77, 0xF7, 0xFB, 0x3E, 0x9D, 0x04, 0x49, 0x23, 0x92, 0x48, 0xA4, 0xA2, 0x58, 0xAB, 0xAE, 0x29,
|
||||
0x62, 0xAE, 0x99, 0x23, 0x92, 0x3A, 0xB9, 0xA2, 0x48, 0xE4, 0xA3, 0x9E, 0x2A, 0xA2, 0xBA, 0x2B, 0xA7, 0x9E, 0x2A, 0xA2,
|
||||
0xBA, 0x2A, 0xE3, 0x8E, 0x78, 0xE7, 0x8E, 0x7D, 0xF8, 0xE4, 0x13, 0x4D, 0xF4, 0x6B, 0xF5, 0x44, 0xC0, 0x79, 0x59, 0xAF,
|
||||
0xEA, 0xFE, 0x28, 0x79, 0x49, 0x79, 0x8D, 0xCC, 0x77, 0xE6, 0x85, 0x5D, 0x9E, 0x67, 0xAA, 0x37, 0x3D, 0xA2, 0x3B, 0x4B,
|
||||
0x89, 0x7B, 0x52, 0xCB, 0x51, 0xA7, 0x9C, 0x8E, 0x36, 0x5E, 0x6E, 0x6E, 0xB8, 0xE7, 0x9E, 0x3B, 0x6B, 0x4A, 0xB3, 0xB7,
|
||||
0xAA, 0x4E, 0x67, 0xA3, 0xE3, 0x73, 0x93, 0xC7, 0xC3, 0x55, 0xCF, 0x3C, 0xD7, 0x3C, 0x77, 0x92, 0x48, 0x1C, 0xDB, 0xFA,
|
||||
0x96, 0xBF, 0xE7, 0x33, 0xA5, 0xFF, 0x00, 0xFA, 0xC7, 0xAF, 0xFF, 0x00, 0xDD, 0x5E, 0xD8, 0x07, 0x49, 0xFD, 0x3D, 0xBC,
|
||||
0x99, 0xE8, 0xBF, 0x55, 0x8F, 0x08, 0x72, 0x5E, 0x08, 0x79, 0x29, 0x99, 0x8F, 0x8E, 0xEA, 0xD6, 0xF4, 0x5B, 0x6D, 0x52,
|
||||
0xFE, 0x3B, 0xC9, 0xAC, 0x6D, 0x76, 0x4D, 0xAB, 0x09, 0xAB, 0x53, 0x4F, 0xF4, 0x1B, 0xB7, 0x7A, 0xFE, 0xE6, 0xF3, 0xEF,
|
||||
0x71, 0x91, 0xDB, 0xB4, 0xF8, 0xAC, 0x2D, 0x2A, 0xCA, 0xD3, 0xF0, 0x92, 0x4E, 0x2E, 0xE0, 0xAA, 0x6B, 0x88, 0xEB, 0xB4,
|
||||
0xBC, 0xAA, 0x9E, 0x42, 0x39, 0xDE, 0x64, 0xFA, 0x56, 0xF9, 0x75, 0xE1, 0xB6, 0xD1, 0x99, 0x83, 0x64, 0xEB, 0xBC, 0xF7,
|
||||
0x62, 0xF5, 0x85, 0xBD, 0xC5, 0xD4, 0xB8, 0x0E, 0xE6, 0xEB, 0xAC, 0x16, 0x53, 0x3F, 0xA7, 0x64, 0xB0, 0xD1, 0xD7, 0x5D,
|
||||
0x56, 0xB7, 0x5B, 0x1C, 0x58, 0xF8, 0xAF, 0xAF, 0x74, 0x1C, 0xBF, 0x36, 0xDC, 0x71, 0xF8, 0x8B, 0x2C, 0xA7, 0xDB, 0xA6,
|
||||
0x99, 0xA9, 0x93, 0x8B, 0x69, 0xEE, 0xE0, 0xA6, 0x9B, 0x8A, 0xC3, 0x4D, 0xBA, 0x9B, 0xA1, 0xFB, 0xAB, 0xBE, 0x33, 0xD6,
|
||||
0xFA, 0xCF, 0x4C, 0x75, 0x56, 0xFD, 0xD9, 0xD9, 0xAB, 0x8B, 0xB8, 0x2C, 0xBF, 0x0B, 0xA5, 0xEA, 0xF9, 0x7C, 0xF4, 0x76,
|
||||
0x93, 0x4F, 0xF9, 0xD3, 0x5E, 0x56, 0xFA, 0xC6, 0xD6, 0x5B, 0x0C, 0x35, 0xA4, 0x71, 0xFB, 0xC9, 0x2D, 0xC5, 0xDC, 0xB0,
|
||||
0x41, 0x0C, 0x54, 0xD5, 0x24, 0x95, 0xD3, 0x45, 0x3C, 0xD5, 0xC0, 0x4C, 0x2B, 0xD3, 0x9F, 0xC0, 0xDE, 0xB7, 0xF4, 0x90,
|
||||
0xEA, 0x0D, 0xFF, 0x00, 0xCC, 0x8F, 0x34, 0xF7, 0x4D, 0x5B, 0x01, 0xDA, 0x97, 0x9A, 0xA4, 0xF8, 0xAB, 0xDA, 0x22, 0xC8,
|
||||
0xDB, 0xE4, 0xF0, 0xFD, 0x65, 0xAB, 0x5C, 0xCB, 0x16, 0x47, 0x9D, 0x1F, 0x57, 0x9A, 0x0F, 0x7E, 0x77, 0x4E, 0xCF, 0xDC,
|
||||
0xEF, 0xB1, 0xD0, 0x45, 0x37, 0xEC, 0xFA, 0x67, 0xF9, 0xD7, 0x15, 0x16, 0x56, 0x1C, 0xCB, 0x1D, 0x57, 0x13, 0xDD, 0x84,
|
||||
0x55, 0xFC, 0xE9, 0xF2, 0xCB, 0x63, 0xF3, 0x5B, 0xC9, 0xBE, 0xC6, 0xEF, 0xDC, 0xED, 0xAD, 0xC6, 0x27, 0x1D, 0xB0, 0x5E,
|
||||
0xC1, 0x89, 0xD1, 0xF5, 0x9B, 0x89, 0xA8, 0x9E, 0xBD, 0x4F, 0xAF, 0xF0, 0x31, 0xF3, 0x63, 0xAB, 0x60, 0xAB, 0x92, 0x2F,
|
||||
0x78, 0x2B, 0xBE, 0xA6, 0xD3, 0x8A, 0xAE, 0xAF, 0xAB, 0x8F, 0xFA, 0xB9, 0x72, 0x37, 0x57, 0x12, 0x51, 0xC7, 0x14, 0xD7,
|
||||
0xC7, 0x1C, 0x06, 0xA2, 0x03, 0xB0, 0x9E, 0x93, 0x1E, 0x9A, 0x3A, 0x07, 0xA8, 0x66, 0xC5, 0xDA, 0xB0, 0xF6, 0x07, 0x74,
|
||||
0x73, 0xA0, 0xE3, 0x7A, 0xEB, 0x01, 0x1D, 0x76, 0xBA, 0x7E, 0xA1, 0x5E, 0x3A, 0x7E, 0xCB, 0xCC, 0x65, 0x33, 0x50, 0xCD,
|
||||
0x6F, 0x88, 0xDA, 0x79, 0xB3, 0xCE, 0x63, 0xEE, 0xF1, 0x74, 0x68, 0x38, 0x2C, 0x97, 0x11, 0xD3, 0x7D, 0x54, 0x7C, 0x49,
|
||||
0x73, 0x75, 0x35, 0x74, 0xDB, 0x71, 0x5D, 0x9F, 0x32, 0xD1, 0x72, 0x0D, 0x27, 0xF2, 0x9F, 0xC2, 0xDF, 0x21, 0xBC, 0x3E,
|
||||
0xEC, 0x9C, 0x97, 0x5C, 0xF7, 0x1F, 0x5F, 0x67, 0x71, 0x9C, 0xC7, 0x97, 0xAB, 0x19, 0xAB, 0xEE, 0x36, 0x38, 0xCB, 0xEB,
|
||||
0xDD, 0x23, 0x7F, 0xB7, 0x9E, 0xB9, 0xF9, 0xC5, 0x64, 0x74, 0xDD, 0x8E, 0x2B, 0x7E, 0x6C, 0x32, 0xBC, 0x65, 0x2D, 0xA0,
|
||||
0xE6, 0x4E, 0x2D, 0x3E, 0x54, 0xDF, 0xDB, 0x55, 0xC5, 0x51, 0x5C, 0x43, 0x14, 0xD1, 0xD7, 0x1D, 0x21, 0x28, 0x7F, 0xA7,
|
||||
0x97, 0xC4, 0x9E, 0xE8, 0xE8, 0x1D, 0x1F, 0xBD, 0x3B, 0xF7, 0xBA, 0x30, 0x39, 0x8E, 0xB1, 0xD6, 0x3B, 0x6B, 0x1B, 0xA5,
|
||||
0x63, 0xB4, 0xAD, 0x67, 0x6F, 0x82, 0xE7, 0x5F, 0xCB, 0xE4, 0xF0, 0x1A, 0x7F, 0x3B, 0x1E, 0x63, 0x21, 0xD8, 0x39, 0xAC,
|
||||
0x3E, 0x4E, 0x9B, 0x59, 0x70, 0xF8, 0x19, 0x28, 0xCE, 0xD1, 0x16, 0x2A, 0x6B, 0xAA, 0x68, 0x92, 0xE6, 0x0F, 0xC4, 0xDC,
|
||||
0x53, 0x4D, 0x36, 0xB5, 0xDB, 0xCD, 0x70, 0x1C, 0xDF, 0xF4, 0xF6, 0xEC, 0x8D, 0x67, 0xB8, 0x3D, 0x7D, 0xB2, 0xBD, 0xA3,
|
||||
0xA5, 0xD7, 0x44, 0xDA, 0x86, 0xF9, 0xDB, 0x5E, 0x58, 0xEC, 0xDA, 0xC5, 0xDD, 0x11, 0xD3, 0x17, 0x19, 0x1C, 0x0E, 0x53,
|
||||
0x40, 0xED, 0x5B, 0x8C, 0x4E, 0x5A, 0xA8, 0xE9, 0xFC, 0xA8, 0x97, 0x2F, 0x63, 0x55, 0x17, 0x55, 0xF1, 0xEF, 0xCF, 0x3C,
|
||||
0x57, 0x2F, 0x3E, 0xFC, 0xF3, 0xCF, 0xE7, 0xC8, 0x62, 0x7F, 0xA8, 0x37, 0xFC, 0x46, 0xB6, 0x8F, 0xE1, 0x47, 0x56, 0x7F,
|
||||
0xD2, 0x2F, 0x01, 0xD5, 0x6F, 0x45, 0xFF, 0x00, 0x33, 0xFA, 0x77, 0xCA, 0x9F, 0x18, 0x72, 0x3E, 0x9B, 0x5E, 0x4B, 0xCB,
|
||||
0x8A, 0xBD, 0xD8, 0xF1, 0xBA, 0x96, 0x7F, 0x47, 0xD3, 0x31, 0x5B, 0x15, 0xCC, 0x36, 0x90, 0x76, 0xB7, 0x51, 0x64, 0x6D,
|
||||
0xEE, 0xE6, 0xA3, 0x5D, 0xC2, 0x5D, 0xFD, 0xC8, 0x25, 0xA3, 0x77, 0xEB, 0xAB, 0x69, 0x64, 0xA2, 0xDE, 0x3B, 0x7E, 0x63,
|
||||
0xBC, 0x8F, 0x1B, 0x6D, 0x6D, 0x77, 0x6D, 0x55, 0x52, 0xDA, 0x5C, 0xCB, 0x10, 0x71, 0x87, 0xCE, 0xFF, 0x00, 0x47, 0x6F,
|
||||
0x28, 0xFC, 0x41, 0xDC, 0x73, 0x39, 0x0D, 0x3F, 0x4A, 0xDA, 0xFB, 0xBB, 0xA2, 0x2E, 0xB2, 0x37, 0x32, 0x6A, 0x7D, 0x91,
|
||||
0xA2, 0xE0, 0xEF, 0x36, 0x5C, 0xA6, 0x2B, 0x15, 0x24, 0xDE, 0xF6, 0x78, 0xFE, 0xCB, 0xD7, 0xB0, 0x36, 0x93, 0xE4, 0x35,
|
||||
0x5C, 0xC5, 0xA5, 0x12, 0x47, 0x0C, 0x97, 0xB5, 0x41, 0x4E, 0x22, 0xF2, 0x5A, 0xA9, 0xFC, 0x3C, 0xFC, 0x49, 0x5D, 0x56,
|
||||
0xD1, 0x07, 0x34, 0x3A, 0xEF, 0xA8, 0xBB, 0x53, 0xB7, 0x36, 0x28, 0xF5, 0x1E, 0xAD, 0xEB, 0x8D, 0xE3, 0xB0, 0xF6, 0x79,
|
||||
0x2E, 0xA0, 0xB2, 0xFD, 0x85, 0xA6, 0x6A, 0xF9, 0x9D, 0x8F, 0x25, 0x0D, 0xC5, 0xCD, 0x72, 0xC7, 0x0D, 0x17, 0x76, 0xB8,
|
||||
0xAB, 0x3B, 0x99, 0x2C, 0xA9, 0xE6, 0xAB, 0x79, 0x39, 0xE6, 0xB9, 0xB8, 0xA2, 0x8A, 0x69, 0x8E, 0xBA, 0xAA, 0xE7, 0x8E,
|
||||
0x28, 0xAB, 0x9E, 0x02, 0x72, 0x5E, 0x13, 0xF4, 0x07, 0x60, 0x78, 0x5B, 0xE9, 0x1B, 0xD9, 0xFA, 0x3F, 0x91, 0x7C, 0x6B,
|
||||
0xBA, 0x06, 0xCD, 0xFD, 0x02, 0xEF, 0xAD, 0xCF, 0x33, 0x63, 0x79, 0xB1, 0xE3, 0x24, 0xB6, 0xD5, 0xAC, 0xF7, 0x0D, 0x72,
|
||||
0xFE, 0x3C, 0x3E, 0x2B, 0x61, 0xCC, 0xF1, 0x2D, 0x18, 0x3B, 0x7C, 0xDD, 0x55, 0xF1, 0x45, 0x32, 0x45, 0x05, 0xCD, 0xC4,
|
||||
0x34, 0xC9, 0x35, 0x11, 0xF1, 0x2D, 0x52, 0x73, 0x55, 0x14, 0x87, 0x25, 0xBE, 0x99, 0x3F, 0xDF, 0xBF, 0x93, 0x7F, 0xC2,
|
||||
0x4D, 0x4F, 0xF9, 0xC6, 0xA0, 0x71, 0x6B, 0xD4, 0x47, 0xFE, 0x7D, 0x7C, 0xCB, 0xFF, 0x00, 0xEC, 0xE7, 0x76, 0xFF, 0x00,
|
||||
0xDC, 0x4D, 0x80, 0x1F, 0x19, 0xE2, 0x67, 0x95, 0x9D, 0xB1, 0xE1, 0xAF, 0x75, 0xEB, 0x1D, 0xDD, 0xD4, 0x39, 0x6F, 0xC2,
|
||||
0x66, 0x70, 0xB3, 0x53, 0x69, 0x9E, 0xC0, 0x5D, 0xD7, 0x2F, 0x3A, 0xFE, 0xF3, 0xAA, 0x5C, 0x5C, 0x5B, 0xCB, 0x9A, 0xD3,
|
||||
0x76, 0x7B, 0x48, 0xF9, 0xE3, 0x9B, 0x9C, 0x3E, 0x5E, 0x2B, 0x7A, 0x78, 0xF9, 0xD3, 0xED, 0x3D, 0xAC, 0xF4, 0x47, 0x71,
|
||||
0x05, 0x71, 0xCF, 0x14, 0x72, 0x52, 0x16, 0x1F, 0xF8, 0x61, 0xE4, 0xE7, 0x45, 0xF9, 0x95, 0xD5, 0x16, 0x9E, 0x45, 0xF4,
|
||||
0xCC, 0x18, 0xFB, 0x4B, 0xED, 0xBA, 0x2C, 0x6E, 0x0F, 0xB1, 0xF1, 0x72, 0x45, 0x63, 0x1E, 0xE3, 0xAC, 0x6D, 0x9A, 0xD5,
|
||||
0xA5, 0x5E, 0xFA, 0x7E, 0xEB, 0x25, 0xAD, 0x34, 0xCB, 0x75, 0x79, 0x81, 0x87, 0x2B, 0xCD, 0x56, 0x53, 0xD7, 0xFD, 0x5D,
|
||||
0xCD, 0x85, 0xCC, 0x53, 0xC3, 0xFD, 0x54, 0xB4, 0x71, 0xC0, 0x57, 0x61, 0xD1, 0x7D, 0x0F, 0xB8, 0x79, 0x3B, 0xE4, 0x9E,
|
||||
0x91, 0xD0, 0xBA, 0x24, 0x5C, 0xD5, 0xB1, 0xF6, 0x67, 0x60, 0xD5, 0xAF, 0xC3, 0x79, 0xCC, 0x35, 0xDC, 0x41, 0x84, 0xC5,
|
||||
0xF3, 0x79, 0x73, 0x79, 0xB1, 0x6C, 0xD7, 0xD1, 0x47, 0xCD, 0x32, 0x57, 0x8C, 0xD5, 0xF5, 0xEB, 0x4B, 0xAC, 0x8D, 0xCF,
|
||||
0x14, 0xF3, 0xF2, 0xE6, 0xDE, 0xDA, 0xBF, 0x8F, 0xBD, 0x5E, 0xDC, 0x72, 0x12, 0x62, 0xF5, 0xD8, 0xEE, 0xFD, 0x4F, 0xC5,
|
||||
0x6F, 0x15, 0xFA, 0x1B, 0xD3, 0x87, 0xA3, 0xE7, 0x8F, 0x0B, 0x8E, 0xCC, 0xEA, 0xF8, 0x1B, 0xAD, 0xC3, 0x1F, 0x6B, 0x73,
|
||||
0x4F, 0x19, 0x3B, 0x0E, 0xA3, 0xEB, 0xF9, 0xAD, 0xEC, 0x75, 0x4B, 0x1C, 0xBD, 0x50, 0xF1, 0x0D, 0x53, 0xDD, 0x76, 0x1E,
|
||||
0xE9, 0x8D, 0x9A, 0xFA, 0xEA, 0xE3, 0x9E, 0x3E, 0x77, 0x32, 0x61, 0xAE, 0x3E, 0xEF, 0x1C, 0xF1, 0x71, 0x57, 0x35, 0x04,
|
||||
0x46, 0x01, 0xB0, 0xBE, 0x28, 0xF9, 0x09, 0xB2, 0xF8, 0xAB, 0xE4, 0x57, 0x52, 0xF7, 0xFE, 0xAB, 0xF7, 0xE5, 0xC8, 0x75,
|
||||
0xBE, 0xDD, 0x61, 0x97, 0xBF, 0xC6, 0xDB, 0xCF, 0xCD, 0xBF, 0x39, 0xFD, 0x62, 0xE3, 0x89, 0x31, 0x9B, 0x7E, 0xB1, 0x24,
|
||||
0xBE, 0xFC, 0x71, 0x44, 0x3B, 0x2E, 0xAF, 0x7D, 0x77, 0x63, 0x55, 0x5C, 0xFB, 0xF1, 0x47, 0x13, 0xFC, 0xBF, 0xB6, 0x9E,
|
||||
0x01, 0x28, 0x5F, 0x5E, 0x8F, 0x1C, 0x75, 0x5F, 0x26, 0x3C, 0x62, 0xEA, 0x0F, 0x50, 0xBE, 0x93, 0xE2, 0x1D, 0x86, 0x8D,
|
||||
0x4F, 0x59, 0xD7, 0x78, 0xD9, 0xB2, 0xD8, 0xC8, 0x38, 0xAE, 0x6D, 0x8F, 0xA3, 0x7B, 0x02, 0xB8, 0x32, 0x7A, 0xB6, 0x7A,
|
||||
0xE2, 0x98, 0x63, 0x9A, 0xE2, 0xA9, 0x74, 0x7D, 0x9B, 0x35, 0x4F, 0xCE, 0x2F, 0xD3, 0xF8, 0x7B, 0x6C, 0xC5, 0xDC, 0x93,
|
||||
0x73, 0xC7, 0x16, 0xDE, 0xD4, 0x87, 0xAB, 0xF4, 0xC9, 0x7E, 0xE3, 0x7C, 0x9E, 0xFE, 0x2B, 0xE9, 0xDF, 0xCA, 0x17, 0x00,
|
||||
0x8D, 0x2E, 0x6F, 0xC0, 0xCF, 0x39, 0x65, 0xCC, 0xE5, 0xE5, 0x8B, 0xC3, 0x1F, 0x2B, 0xE4, 0x8A, 0x4C, 0x9D, 0xFC, 0x91,
|
||||
0xC9, 0x1F, 0x8E, 0xBD, 0xBF, 0x5C, 0x72, 0x47, 0x5D, 0xD4, 0xB5, 0x51, 0x5D, 0x15, 0xD3, 0xA7, 0xF3, 0x4D, 0x74, 0x57,
|
||||
0x4F, 0x3C, 0x73, 0xC7, 0x3C, 0x73, 0xED, 0xCF, 0x00, 0xC0, 0x7D, 0x99, 0xD3, 0x5D, 0xBF, 0xD2, 0xB9, 0x5C, 0x7E, 0x0B,
|
||||
0xB9, 0x3A, 0xA7, 0xB2, 0x7A, 0x97, 0x39, 0x96, 0xC7, 0xFE, 0xD6, 0xC5, 0xE1, 0xBB, 0x33, 0x46, 0xD9, 0xF4, 0x3C, 0xAE,
|
||||
0x4B, 0x15, 0xF8, 0x99, 0xAC, 0xFF, 0x00, 0x69, 0xE3, 0xF1, 0xDB, 0x4E, 0x2F, 0x15, 0x77, 0x79, 0x8F, 0xFC, 0x5D, 0xB4,
|
||||
0x91, 0x7D, 0xE8, 0xE8, 0xAA, 0x3F, 0xB9, 0x1D, 0x54, 0xFC, 0xBE, 0x54, 0xF3, 0xC7, 0x01, 0x8D, 0x80, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xD7, 0xAF, 0xFC, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xB9, 0xAC, 0x6C,
|
||||
0x39, 0x1D, 0x4B, 0x64, 0xD7, 0xB6, 0xBC, 0x47, 0x30, 0xD3, 0x96, 0xD6, 0x73, 0x98, 0x9D, 0x87, 0x17, 0x55, 0xC4, 0x5F,
|
||||
0x7E, 0xDE, 0x9C, 0x8E, 0x16, 0xFE, 0xDF, 0x25, 0x65, 0xCC, 0xF0, 0xFC, 0xA9, 0xFB, 0xD0, 0xF1, 0x73, 0x6D, 0x4F, 0xCA,
|
||||
0x9F, 0x7E, 0x3E, 0x54, 0xFB, 0xF1, 0xEE, 0x0D, 0xC8, 0xF3, 0x1F, 0xD4, 0x3B, 0xC9, 0x1F, 0x3B, 0x2D, 0xBA, 0xFA, 0xD7,
|
||||
0xBF, 0xB2, 0xBA, 0x96, 0x4A, 0x1E, 0xB2, 0x9F, 0x67, 0xB8, 0xD5, 0xB8, 0xD6, 0x35, 0x4B, 0x3D, 0x6B, 0x98, 0x64, 0xDB,
|
||||
0xA3, 0xC0, 0x47, 0x99, 0xE6, 0xF6, 0xAB, 0x59, 0xA5, 0xE6, 0xF3, 0x8A, 0xE9, 0xD6, 0xED, 0x7E, 0xDF, 0x15, 0x7B, 0x7D,
|
||||
0xBF, 0x6A, 0xBD, 0xBF, 0xF7, 0x7E, 0x41, 0xA3, 0x60, 0xF5, 0xF5, 0xFD, 0x83, 0x39, 0xA9, 0xE7, 0xB0, 0xBB, 0x46, 0xB1,
|
||||
0x97, 0xC9, 0x6B, 0xFB, 0x26, 0xB9, 0x95, 0xC7, 0xE7, 0x70, 0x19, 0xEC, 0x35, 0xE5, 0xC6, 0x3B, 0x2D, 0x85, 0xCC, 0xE2,
|
||||
0x6E, 0xE2, 0xBE, 0xC6, 0x65, 0x71, 0x97, 0xF6, 0xB2, 0x45, 0x73, 0x65, 0x90, 0xC7, 0xDE, 0xC1, 0x44, 0xB0, 0xCB, 0x1D,
|
||||
0x54, 0xD7, 0x1C, 0x94, 0x71, 0x55, 0x3C, 0xF1, 0xCF, 0x1C, 0x72, 0x0D, 0xB6, 0xF3, 0x53, 0xCD, 0xCE, 0xCC, 0xF3, 0x9F,
|
||||
0x6D, 0xEA, 0xFD, 0xF7, 0xB6, 0xB1, 0x58, 0x1B, 0x3D, 0xCB, 0xAE, 0xFA, 0x87, 0x03, 0xD5, 0x37, 0xF9, 0x9C, 0x15, 0x13,
|
||||
0x5B, 0xD3, 0xB9, 0x57, 0x84, 0xCE, 0x6C, 0x79, 0xD9, 0x76, 0xDC, 0x9D, 0x85, 0x7C, 0xFE, 0x13, 0x1B, 0x97, 0xCB, 0x5D,
|
||||
0x6C, 0x72, 0x73, 0x3C, 0x16, 0xBC, 0x51, 0x6B, 0x4D, 0x54, 0x7B, 0xC7, 0x45, 0x14, 0xF3, 0xC5, 0x14, 0x86, 0xA6, 0x6B,
|
||||
0xBB, 0x26, 0xC3, 0xA8, 0x67, 0x71, 0x5B, 0x46, 0xA5, 0x9E, 0xCD, 0x6A, 0xFB, 0x36, 0x0A, 0xF6, 0x0C, 0x9E, 0x0F, 0x62,
|
||||
0xD7, 0x72, 0x97, 0xD8, 0x4C, 0xEE, 0x1B, 0x25, 0x6B, 0x5F, 0xCE, 0xDB, 0x21, 0x8A, 0xCB, 0xE3, 0x67, 0xB6, 0xC8, 0x63,
|
||||
0xAF, 0x6D, 0xEB, 0xE3, 0xDE, 0x89, 0x61, 0x92, 0x89, 0x28, 0xE7, 0xF3, 0xE3, 0x9E, 0x01, 0xDC, 0xCE, 0x8E, 0xFA, 0x87,
|
||||
0x7C, 0xE4, 0xEA, 0xFC, 0x3E, 0x33, 0x5D, 0xEC, 0x3C, 0x6F, 0x57, 0x77, 0xD6, 0x3B, 0x1D, 0x6F, 0xCD, 0xAF, 0xED, 0xCD,
|
||||
0xD7, 0x03, 0x92, 0xD7, 0xF7, 0xDB, 0x88, 0x61, 0x86, 0x58, 0xEC, 0x68, 0x9F, 0x63, 0xD3, 0x32, 0xB8, 0x6C, 0x25, 0xE5,
|
||||
0x70, 0x7B, 0xC7, 0xC4, 0xB3, 0xDD, 0x62, 0x2E, 0x6F, 0x2E, 0xA9, 0x8F, 0xDE, 0x59, 0xB9, 0x9A, 0xBA, 0xE6, 0xA8, 0x33,
|
||||
0x2E, 0xD3, 0xF5, 0x30, 0x79, 0x3F, 0x7F, 0x87, 0x9E, 0xD7, 0x50, 0xE8, 0x2E, 0x8D, 0xD6, 0xF3, 0x52, 0xF3, 0xF0, 0x8B,
|
||||
0x2F, 0x99, 0xBA, 0xDE, 0x76, 0x9B, 0x6B, 0x58, 0xAA, 0xA2, 0x4A, 0x64, 0xAE, 0x1C, 0x4D, 0xBE, 0x7B, 0x5A, 0xF9, 0xDE,
|
||||
0x53, 0x55, 0x54, 0xD5, 0x15, 0x72, 0x4F, 0x5C, 0x54, 0xD5, 0x4F, 0xEB, 0x8A, 0x4E, 0x39, 0xF6, 0xE0, 0x38, 0xAD, 0xE4,
|
||||
0xFF, 0x00, 0x99, 0xDE, 0x4A, 0xF9, 0x8B, 0xB4, 0xD1, 0xB4, 0xF9, 0x03, 0xDA, 0x59, 0xDD, 0xD7, 0xF0, 0x53, 0x4D, 0x2E,
|
||||
0xBF, 0xAC, 0x51, 0xCC, 0x38, 0x6D, 0x17, 0x53, 0xA2, 0x6F, 0x78, 0xFE, 0xDE, 0xB1, 0xA5, 0xE1, 0xE2, 0xB3, 0xD7, 0xF1,
|
||||
0x73, 0x7E, 0x1B, 0xE3, 0x0C, 0xB7, 0x9C, 0x41, 0x5E, 0x42, 0xF2, 0x88, 0xE8, 0xE6, 0xEA, 0xE2, 0x7A, 0xF8, 0xF9, 0xF2,
|
||||
0x1A, 0xBA, 0x00, 0x32, 0x7F, 0x4E, 0x77, 0x4F, 0x6A, 0x78, 0xFB, 0xD8, 0x38, 0x3E, 0xD4, 0xE9, 0x8D, 0xE3, 0x39, 0xD7,
|
||||
0xBB, 0xFE, 0xB9, 0x24, 0x95, 0xE2, 0xB6, 0x2C, 0x0C, 0xF1, 0xD1, 0x3D, 0x31, 0x4F, 0x4F, 0xDB, 0xBA, 0xB0, 0xBE, 0xB3,
|
||||
0xBA, 0x8A, 0xE7, 0x1B, 0x98, 0xC4, 0x5F, 0xC5, 0xFA, 0x2E, 0x6C, 0xAF, 0x21, 0x9E, 0xD2, 0xE6, 0x3F, 0xD3, 0x2C, 0x75,
|
||||
0xD3, 0xF9, 0x03, 0xBE, 0x5A, 0x57, 0xD4, 0xB5, 0xE5, 0x3E, 0x23, 0x03, 0x6D, 0x8F, 0xDE, 0x3A, 0x3B, 0xA4, 0x77, 0x4C,
|
||||
0xE5, 0xB7, 0xC2, 0x2A, 0xB6, 0x1C, 0x6C, 0x9B, 0x96, 0xA1, 0xCD, 0xFC, 0x11, 0xDB, 0x5B, 0xC5, 0xC4, 0xD9, 0x1C, 0x4D,
|
||||
0x19, 0xBC, 0xED, 0x9F, 0x39, 0x49, 0xEE, 0x28, 0x96, 0x59, 0x64, 0xB5, 0xE6, 0xD6, 0xDB, 0x9F, 0xB9, 0xC5, 0x31, 0xDB,
|
||||
0xC5, 0xC5, 0x3F, 0xA8, 0x34, 0xF3, 0xCC, 0x7F, 0x5A, 0xFF, 0x00, 0x31, 0x7C, 0xBE, 0xD5, 0x33, 0x3D, 0x69, 0x35, 0xE6,
|
||||
0xB1, 0xD3, 0x1D, 0x53, 0x9F, 0xB5, 0xE7, 0x1F, 0x9F, 0xD4, 0x3A, 0xB6, 0xDF, 0x29, 0x67, 0x94, 0xDA, 0xB1, 0x72, 0x53,
|
||||
0xED, 0x73, 0x8C, 0xDB, 0x37, 0x2C, 0xBE, 0x4B, 0x21, 0x9C, 0xBE, 0xC6, 0x5E, 0x7C, 0xAB, 0x8E, 0xE2, 0xD2, 0xC7, 0xF6,
|
||||
0x6D, 0x95, 0xDD, 0xB5, 0x5F, 0x66, 0xE6, 0x09, 0xE9, 0xF9, 0xF3, 0x58, 0x73, 0xDB, 0xC6, 0xCF, 0x22, 0xFB, 0x2F, 0xC5,
|
||||
0x1E, 0xE3, 0xD5, 0xBB, 0xD7, 0xA8, 0x6E, 0xF1, 0x16, 0x5B, 0xFE, 0x9F, 0x06, 0x7E, 0xDF, 0x0B, 0x73, 0x9D, 0xC4, 0xC3,
|
||||
0x9C, 0xC5, 0xD1, 0x1E, 0xCB, 0xAE, 0xE5, 0x35, 0x7C, 0xA7, 0x17, 0x18, 0xCB, 0x8A, 0xE3, 0x8A, 0x7E, 0x6B, 0xC5, 0x66,
|
||||
0x26, 0xE2, 0x8E, 0x79, 0xE7, 0x8F, 0x85, 0x7C, 0xF1, 0x57, 0xF9, 0x03, 0xD6, 0xF2, 0x93, 0xCA, 0x4E, 0xD7, 0xF3, 0x0B,
|
||||
0xB5, 0xEE, 0xFB, 0xA3, 0xBA, 0x2E, 0xF0, 0x77, 0xDB, 0xC5, 0xF6, 0x0F, 0x0B, 0xAF, 0x5C, 0x5C, 0x6B, 0xD8, 0x58, 0x70,
|
||||
0x38, 0xEA, 0xF1, 0xD8, 0x18, 0x65, 0x83, 0x1D, 0xC7, 0x18, 0xE8, 0x25, 0x96, 0x2A, 0x26, 0xA2, 0x29, 0x79, 0xE2, 0xAA,
|
||||
0xB8, 0xE7, 0x8F, 0x97, 0xB7, 0x1F, 0x97, 0xBF, 0xF6, 0x86, 0x00, 0xC7, 0x64, 0x72, 0x18, 0x7C, 0x85, 0x86, 0x5F, 0x11,
|
||||
0x7F, 0x79, 0x8B, 0xCA, 0xE2, 0xEF, 0x2D, 0x72, 0x38, 0xCC, 0x9E, 0x3A, 0xEA, 0x7B, 0x1C, 0x86, 0x3B, 0x21, 0x63, 0x3C,
|
||||
0x77, 0x36, 0x57, 0xF6, 0x17, 0xB6, 0xD2, 0x45, 0x73, 0x67, 0x79, 0x67, 0x73, 0x15, 0x32, 0x45, 0x2C, 0x75, 0x53, 0x5C,
|
||||
0x75, 0xD3, 0xC5, 0x54, 0xF3, 0xC7, 0x3C, 0x71, 0xCF, 0x01, 0xDB, 0xBF, 0x1E, 0xBE, 0xA0, 0x2F, 0x3A, 0x7A, 0x5F, 0x13,
|
||||
0x8E, 0xD6, 0x77, 0x8B, 0x8D, 0x17, 0xC8, 0x4D, 0x7E, 0xC2, 0x3A, 0x2D, 0xE3, 0xBD, 0xED, 0x0C, 0x56, 0x52, 0x1D, 0xF6,
|
||||
0x3B, 0x48, 0x21, 0xB9, 0xA6, 0x18, 0xA3, 0xDE, 0x35, 0x8C, 0xB6, 0x1A, 0x5C, 0x94, 0xF5, 0x5C, 0x4B, 0x1D, 0x53, 0x5C,
|
||||
0xE5, 0xEC, 0xF2, 0xD7, 0x52, 0xD1, 0x17, 0xC7, 0xEE, 0x53, 0x55, 0x5C, 0xD7, 0xC0, 0x6C, 0x9E, 0x67, 0xEA, 0x67, 0xF2,
|
||||
0x42, 0x7C, 0x65, 0xDC, 0x5A, 0xFF, 0x00, 0x8E, 0x7D, 0x23, 0x8C, 0xCC, 0x57, 0x45, 0x1C, 0x58, 0xDF, 0xE6, 0x72, 0xDB,
|
||||
0xE6, 0x77, 0x19, 0x6F, 0x27, 0x12, 0xD1, 0xCC, 0x95, 0x5D, 0xE2, 0x6C, 0xB3, 0x1A, 0xED, 0xD5, 0xE5, 0x15, 0x43, 0xC5,
|
||||
0x54, 0xF1, 0x4D, 0x17, 0xB0, 0x73, 0x4D, 0x5C, 0xF1, 0x57, 0xBF, 0x3C, 0x71, 0xCD, 0x35, 0x07, 0x1F, 0x7C, 0xB3, 0xF5,
|
||||
0x0C, 0xF2, 0xCB, 0xCD, 0x5B, 0xC8, 0x69, 0xEF, 0x4E, 0xCF, 0xBE, 0xC8, 0xEA, 0x96, 0x17, 0x3C, 0x5E, 0x61, 0xFA, 0xDB,
|
||||
0x59, 0xB6, 0x8B, 0x55, 0xEB, 0x9C, 0x4D, 0xCD, 0x14, 0xF1, 0xC4, 0x77, 0x54, 0x6B, 0x58, 0xCE, 0x68, 0xA3, 0x33, 0x91,
|
||||
0x83, 0x9E, 0x6B, 0xE6, 0x2B, 0xDC, 0xA4, 0xB7, 0xF7, 0xD0, 0xD3, 0x2D, 0x74, 0x47, 0x35, 0x31, 0xD5, 0xF0, 0xE0, 0x3C,
|
||||
0x9F, 0x0F, 0xBC, 0xE5, 0xEF, 0xBF, 0x06, 0xB6, 0x4D, 0xC7, 0x6B, 0xE8, 0x4C, 0x86, 0xB1, 0x8E, 0xCC, 0x6F, 0x58, 0x3B,
|
||||
0x0D, 0x7B, 0x3D, 0x2E, 0xCD, 0xAD, 0xDB, 0x6C, 0x90, 0xD7, 0x8D, 0xC7, 0x5F, 0xD5, 0x92, 0xB7, 0x8E, 0xD6, 0x0B, 0x99,
|
||||
0xA2, 0xA2, 0xDA, 0x5F, 0xC5, 0x55, 0xEF, 0x55, 0x7C, 0x7B, 0xF3, 0xCF, 0x1C, 0x7B, 0x7E, 0x5F, 0x9F, 0xB8, 0x6B, 0xDF,
|
||||
0x6A, 0xF6, 0x56, 0xD1, 0xDC, 0x9D, 0x99, 0xBF, 0xF6, 0xD6, 0xED, 0x35, 0x9D, 0xC6, 0xE1, 0xD9, 0x7B, 0x8E, 0xC5, 0xBD,
|
||||
0x6D, 0x13, 0xE3, 0xEC, 0xE8, 0xC7, 0xD8, 0x4D, 0x9F, 0xDA, 0x32, 0xB7, 0x59, 0x9C, 0xAC, 0x96, 0x76, 0x31, 0x73, 0x54,
|
||||
0x76, 0x76, 0xB5, 0xDE, 0xDE, 0x57, 0xCD, 0x11, 0x53, 0xCF, 0x3C, 0x51, 0x4F, 0xB7, 0x1F, 0xE4, 0x0F, 0x81, 0x06, 0xED,
|
||||
0xF8, 0x2B, 0xE7, 0x97, 0x73, 0x78, 0x0D, 0xDA, 0xB7, 0x3D, 0x8B, 0xD5, 0x92, 0xDA, 0xE6, 0xB0, 0xBB, 0x06, 0x3B, 0x9C,
|
||||
0x46, 0xF9, 0xD7, 0x19, 0xEB, 0x9B, 0xD8, 0xF5, 0x2D, 0xE3, 0x1F, 0x0C, 0x77, 0x5C, 0xE2, 0x6B, 0xC9, 0xC5, 0x67, 0x25,
|
||||
0x13, 0x5A, 0xE5, 0xF5, 0xFB, 0xDB, 0xAA, 0xA7, 0xB0, 0xBD, 0x8B, 0xDA, 0x7B, 0x7E, 0x6B, 0x96, 0x2F, 0x7A, 0xA0, 0x9E,
|
||||
0x78, 0xE4, 0x0F, 0x94, 0xF1, 0x5F, 0xCC, 0xBE, 0xE1, 0xF0, 0xDF, 0xB3, 0x76, 0x1E, 0xDD, 0xE9, 0x58, 0xB4, 0xBB, 0x5D,
|
||||
0xDF, 0x62, 0xC1, 0x64, 0x75, 0xB9, 0x32, 0x7B, 0x5E, 0xAB, 0x67, 0xB5, 0x7E, 0xCB, 0xC4, 0xE5, 0xB2, 0x76, 0x79, 0x5C,
|
||||
0x84, 0x58, 0x5A, 0x2F, 0xA4, 0xA3, 0xF6, 0x6D, 0xCD, 0xDC, 0xD6, 0x11, 0x47, 0x24, 0xD4, 0x73, 0xF7, 0x2A, 0x87, 0x8E,
|
||||
0x63, 0xF7, 0xF8, 0xD7, 0x5F, 0x15, 0x07, 0xC0, 0x79, 0x19, 0xE4, 0x4F, 0x6A, 0x79, 0x55, 0xDB, 0xBB, 0x3F, 0x77, 0x77,
|
||||
0x2E, 0x72, 0x2C, 0xF6, 0xF7, 0xB5, 0xD3, 0x8B, 0x86, 0xFA, 0x7B, 0x3B, 0x4A, 0x31, 0xB8, 0xAB, 0x2B, 0x2C, 0x2E, 0x2E,
|
||||
0xD3, 0x0F, 0x8C, 0xC6, 0xE1, 0xB1, 0x30, 0xD5, 0x55, 0xB6, 0x2F, 0x1D, 0x6B, 0x67, 0x65, 0x4F, 0xB4, 0x51, 0xFB, 0x71,
|
||||
0x54, 0xB5, 0x57, 0x2D, 0x5F, 0x29, 0x24, 0xAE, 0xAA, 0x83, 0x07, 0x00, 0x0E, 0x8F, 0xF5, 0x2F, 0xAA, 0xA7, 0x96, 0xFD,
|
||||
0x3B, 0xE3, 0x8C, 0xFE, 0x29, 0x60, 0x73, 0x3A, 0x2E, 0xC5, 0xD2, 0x97, 0x18, 0x3D, 0xBB, 0x57, 0x93, 0x5A, 0xDE, 0xF4,
|
||||
0x7C, 0x76, 0xD7, 0x2F, 0xF4, 0x67, 0x78, 0xAF, 0x23, 0x26, 0xC1, 0xAF, 0x7E, 0x3A, 0xF6, 0x6A, 0x65, 0xAB, 0x11, 0x34,
|
||||
0x99, 0x7B, 0x9E, 0x62, 0x8A, 0xAE, 0x2A, 0xE2, 0x1E, 0x26, 0xE6, 0x9A, 0x3D, 0xA9, 0xE2, 0x9A, 0x69, 0x0F, 0x99, 0xF0,
|
||||
0xFB, 0xD4, 0x9F, 0xC9, 0xEF, 0x06, 0xB5, 0xBD, 0xC7, 0x54, 0xE8, 0x4C, 0xAE, 0x9B, 0x8D, 0xC4, 0xEF, 0x59, 0xCB, 0x1D,
|
||||
0x87, 0x60, 0xA7, 0x66, 0xD4, 0x6C, 0xF6, 0x4B, 0x89, 0x72, 0x38, 0xEB, 0x0E, 0x71, 0xB6, 0xBC, 0xDB, 0x4D, 0x75, 0x3C,
|
||||
0x5F, 0x86, 0x86, 0x8B, 0x6A, 0xB9, 0xF7, 0xA6, 0x9E, 0x3F, 0x55, 0x5C, 0xFB, 0xF3, 0xCF, 0xF6, 0x7B, 0x06, 0xE1, 0x7F,
|
||||
0xE6, 0x0D, 0xF5, 0x1A, 0xFF, 0x00, 0xF2, 0x8E, 0xA8, 0xFF, 0x00, 0xF5, 0x66, 0x23, 0xFF, 0x00, 0xEB, 0x07, 0x3E, 0x7C,
|
||||
0xBE, 0xF3, 0x5F, 0xBD, 0x3C, 0xE1, 0xDD, 0x75, 0x8D, 0xFB, 0xBE, 0x72, 0x3A, 0xE6, 0x47, 0x61, 0xD4, 0x75, 0x7F, 0xE8,
|
||||
0x7E, 0x1A, 0x4D, 0x6B, 0x5D, 0xB6, 0xD6, 0xED, 0x23, 0xC3, 0x7E, 0xD6, 0xC8, 0x66, 0xBE, 0x13, 0xDA, 0xDA, 0xCB, 0x2D,
|
||||
0x33, 0xDC, 0x7E, 0x3B, 0x27, 0x2F, 0x3F, 0x73, 0x9E, 0x7D, 0xFE, 0x3E, 0xDC, 0x7F, 0x90, 0x35, 0x28, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, 0xAF, 0xFC, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF,
|
||||
0xD1, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0xFF, 0xD2, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD3, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD4, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD5, 0xAF, 0xFC, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF,
|
||||
0xD6, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0xFF, 0xD7, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD1, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD2, 0xAF, 0xFC, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF,
|
||||
0xD3, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0xFF, 0xD4, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD5, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD6, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD7, 0xAF, 0xFC, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF,
|
||||
0xD0, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0xFF, 0xD1, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD2, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD3, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD4, 0xAF, 0xFC, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF,
|
||||
0xD5, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0xFF, 0xD6, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD7, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD1, 0xAF, 0xFC, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF,
|
||||
0xD2, 0xAF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0xFF, 0xD9,
|
||||
};
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -73,13 +73,13 @@ void us_encoder_destroy(us_encoder_s *enc) {
|
||||
free(enc);
|
||||
}
|
||||
|
||||
us_encoder_type_e us_encoder_parse_type(const char *str) {
|
||||
int us_encoder_parse_type(const char *str) {
|
||||
US_ARRAY_ITERATE(_ENCODER_TYPES, 0, item, {
|
||||
if (!strcasecmp(item->name, str)) {
|
||||
return item->type;
|
||||
}
|
||||
});
|
||||
return US_ENCODER_TYPE_UNKNOWN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *us_encoder_type_to_string(us_encoder_type_e type) {
|
||||
@@ -91,7 +91,9 @@ const char *us_encoder_type_to_string(us_encoder_type_e type) {
|
||||
return _ENCODER_TYPES[0].name;
|
||||
}
|
||||
|
||||
us_workers_pool_s *us_encoder_workers_pool_init(us_encoder_s *enc, us_device_s *dev) {
|
||||
void us_encoder_open(us_encoder_s *enc, us_device_s *dev) {
|
||||
assert(enc->run->pool == NULL);
|
||||
|
||||
# define DR(x_next) dev->run->x_next
|
||||
|
||||
us_encoder_type_e type = (_ER(cpu_forced) ? US_ENCODER_TYPE_CPU : enc->type);
|
||||
@@ -162,15 +164,20 @@ us_workers_pool_s *us_encoder_workers_pool_init(us_encoder_s *enc, us_device_s *
|
||||
: 0
|
||||
);
|
||||
|
||||
return us_workers_pool_init(
|
||||
enc->run->pool = us_workers_pool_init(
|
||||
"JPEG", "jw", n_workers, desired_interval,
|
||||
_worker_job_init, (void *)enc,
|
||||
_worker_job_init, (void*)enc,
|
||||
_worker_job_destroy,
|
||||
_worker_run_job);
|
||||
|
||||
# undef DR
|
||||
}
|
||||
|
||||
void us_encoder_close(us_encoder_s *enc) {
|
||||
assert(enc->run->pool != NULL);
|
||||
US_DELETE(enc->run->pool, us_workers_pool_destroy);
|
||||
}
|
||||
|
||||
void us_encoder_get_runtime_params(us_encoder_s *enc, us_encoder_type_e *type, unsigned *quality) {
|
||||
US_MUTEX_LOCK(_ER(mutex));
|
||||
*type = _ER(type);
|
||||
@@ -181,25 +188,23 @@ void us_encoder_get_runtime_params(us_encoder_s *enc, us_encoder_type_e *type, u
|
||||
static void *_worker_job_init(void *v_enc) {
|
||||
us_encoder_job_s *job;
|
||||
US_CALLOC(job, 1);
|
||||
job->enc = (us_encoder_s *)v_enc;
|
||||
job->enc = (us_encoder_s*)v_enc;
|
||||
job->dest = us_frame_init();
|
||||
return (void *)job;
|
||||
return (void*)job;
|
||||
}
|
||||
|
||||
static void _worker_job_destroy(void *v_job) {
|
||||
us_encoder_job_s *job = (us_encoder_job_s *)v_job;
|
||||
us_encoder_job_s *job = v_job;
|
||||
us_frame_destroy(job->dest);
|
||||
free(job);
|
||||
}
|
||||
|
||||
static bool _worker_run_job(us_worker_s *wr) {
|
||||
us_encoder_job_s *job = (us_encoder_job_s *)wr->job;
|
||||
us_encoder_job_s *job = wr->job;
|
||||
us_encoder_s *enc = job->enc; // Just for _ER()
|
||||
const us_frame_s *src = &job->hw->raw;
|
||||
us_frame_s *dest = job->dest;
|
||||
|
||||
assert(_ER(type) != US_ENCODER_TYPE_UNKNOWN);
|
||||
|
||||
if (_ER(type) == US_ENCODER_TYPE_CPU) {
|
||||
US_LOG_VERBOSE("Compressing JPEG using CPU: worker=%s, buffer=%u",
|
||||
wr->name, job->hw->buf.index);
|
||||
@@ -223,6 +228,9 @@ static bool _worker_run_job(us_worker_s *wr) {
|
||||
us_frame_encoding_begin(src, dest, V4L2_PIX_FMT_JPEG);
|
||||
usleep(5000); // Просто чтобы работала логика desired_fps
|
||||
dest->encode_end_ts = us_get_now_monotonic(); // us_frame_encoding_end()
|
||||
|
||||
} else {
|
||||
assert(0 && "Unknown encoder type");
|
||||
}
|
||||
|
||||
US_LOG_VERBOSE("Compressed new JPEG: size=%zu, time=%0.3Lf, worker=%s, buffer=%u",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -47,7 +47,6 @@
|
||||
#define ENCODER_TYPES_STR "CPU, HW, M2M-VIDEO, M2M-IMAGE, NOOP"
|
||||
|
||||
typedef enum {
|
||||
US_ENCODER_TYPE_UNKNOWN, // Only for us_encoder_parse_type() and main()
|
||||
US_ENCODER_TYPE_CPU,
|
||||
US_ENCODER_TYPE_HW,
|
||||
US_ENCODER_TYPE_M2M_VIDEO,
|
||||
@@ -63,6 +62,8 @@ typedef struct {
|
||||
|
||||
unsigned n_m2ms;
|
||||
us_m2m_encoder_s **m2ms;
|
||||
|
||||
us_workers_pool_s *pool;
|
||||
} us_encoder_runtime_s;
|
||||
|
||||
typedef struct {
|
||||
@@ -83,10 +84,10 @@ typedef struct {
|
||||
us_encoder_s *us_encoder_init(void);
|
||||
void us_encoder_destroy(us_encoder_s *enc);
|
||||
|
||||
us_encoder_type_e us_encoder_parse_type(const char *str);
|
||||
int us_encoder_parse_type(const char *str);
|
||||
const char *us_encoder_type_to_string(us_encoder_type_e type);
|
||||
|
||||
us_workers_pool_s *us_encoder_workers_pool_init(us_encoder_s *enc, us_device_s *dev);
|
||||
void us_encoder_get_runtime_params(us_encoder_s *enc, us_encoder_type_e *type, unsigned *quality);
|
||||
void us_encoder_open(us_encoder_s *enc, us_device_s *dev);
|
||||
void us_encoder_close(us_encoder_s *enc);
|
||||
|
||||
int us_encoder_compress(us_encoder_s *enc, unsigned worker_number, us_frame_s *src, us_frame_s *dest);
|
||||
void us_encoder_get_runtime_params(us_encoder_s *enc, us_encoder_type_e *type, unsigned *quality);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# Copyright (C) 2005-2006 Laurent Pinchart & Michel Xhaard #
|
||||
# Copyright (C) 2006 Gabriel A. Devenyi #
|
||||
# Copyright (C) 2007 Tom Stöveken #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
@@ -29,8 +29,8 @@
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct jpeg_destination_mgr mgr; // Default manager
|
||||
JOCTET *buf; // Start of buffer
|
||||
struct jpeg_destination_mgr mgr; // Default manager
|
||||
JOCTET *buf; // Start of buffer
|
||||
us_frame_s *frame;
|
||||
} _jpeg_dest_manager_s;
|
||||
|
||||
@@ -63,7 +63,12 @@ void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, unsigned q
|
||||
jpeg.image_width = src->width;
|
||||
jpeg.image_height = src->height;
|
||||
jpeg.input_components = 3;
|
||||
jpeg.in_color_space = ((src->format == V4L2_PIX_FMT_YUYV || src->format == V4L2_PIX_FMT_UYVY) ? JCS_YCbCr : JCS_RGB);
|
||||
switch (src->format) {
|
||||
case V4L2_PIX_FMT_YUYV:
|
||||
case V4L2_PIX_FMT_YVYU:
|
||||
case V4L2_PIX_FMT_UYVY: jpeg.in_color_space = JCS_YCbCr; break;
|
||||
default: jpeg.in_color_space = JCS_RGB; break;
|
||||
}
|
||||
|
||||
jpeg_set_defaults(&jpeg);
|
||||
jpeg_set_quality(&jpeg, quality, TRUE);
|
||||
@@ -89,12 +94,12 @@ void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, unsigned q
|
||||
|
||||
static void _jpeg_set_dest_frame(j_compress_ptr jpeg, us_frame_s *frame) {
|
||||
if (jpeg->dest == NULL) {
|
||||
assert((jpeg->dest = (struct jpeg_destination_mgr *)(*jpeg->mem->alloc_small)(
|
||||
assert((jpeg->dest = (struct jpeg_destination_mgr*)(*jpeg->mem->alloc_small)(
|
||||
(j_common_ptr) jpeg, JPOOL_PERMANENT, sizeof(_jpeg_dest_manager_s)
|
||||
)) != NULL);
|
||||
}
|
||||
|
||||
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s *)jpeg->dest;
|
||||
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s*)jpeg->dest;
|
||||
dest->mgr.init_destination = _jpeg_init_destination;
|
||||
dest->mgr.empty_output_buffer = _jpeg_empty_output_buffer;
|
||||
dest->mgr.term_destination = _jpeg_term_destination;
|
||||
@@ -221,10 +226,10 @@ static void _jpeg_write_scanlines_bgr24(struct jpeg_compress_struct *jpeg, const
|
||||
#define JPEG_OUTPUT_BUFFER_SIZE ((size_t)4096)
|
||||
|
||||
static void _jpeg_init_destination(j_compress_ptr jpeg) {
|
||||
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s *)jpeg->dest;
|
||||
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s*)jpeg->dest;
|
||||
|
||||
// Allocate the output buffer - it will be released when done with image
|
||||
assert((dest->buf = (JOCTET *)(*jpeg->mem->alloc_small)(
|
||||
assert((dest->buf = (JOCTET*)(*jpeg->mem->alloc_small)(
|
||||
(j_common_ptr) jpeg, JPOOL_IMAGE, JPEG_OUTPUT_BUFFER_SIZE * sizeof(JOCTET)
|
||||
)) != NULL);
|
||||
|
||||
@@ -235,7 +240,7 @@ static void _jpeg_init_destination(j_compress_ptr jpeg) {
|
||||
static boolean _jpeg_empty_output_buffer(j_compress_ptr jpeg) {
|
||||
// Called whenever local jpeg buffer fills up
|
||||
|
||||
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s *)jpeg->dest;
|
||||
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s*)jpeg->dest;
|
||||
|
||||
us_frame_append_data(dest->frame, dest->buf, JPEG_OUTPUT_BUFFER_SIZE);
|
||||
|
||||
@@ -249,7 +254,7 @@ static void _jpeg_term_destination(j_compress_ptr jpeg) {
|
||||
// Called by jpeg_finish_compress after all data has been written.
|
||||
// Usually needs to flush buffer.
|
||||
|
||||
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s *)jpeg->dest;
|
||||
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s*)jpeg->dest;
|
||||
const size_t final = JPEG_OUTPUT_BUFFER_SIZE - dest->mgr.free_in_buffer;
|
||||
|
||||
// Write any data remaining in the buffer.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# Copyright (C) 2005-2006 Laurent Pinchart & Michel Xhaard #
|
||||
# Copyright (C) 2006 Gabriel A. Devenyi #
|
||||
# Copyright (C) 2007 Tom Stöveken #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# Copyright (C) 2005-2006 Laurent Pinchart & Michel Xhaard #
|
||||
# Copyright (C) 2006 Gabriel A. Devenyi #
|
||||
# Copyright (C) 2007 Tom Stöveken #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user