Skip to content

Commit

Permalink
JPEG snapshots and MJPEG streams now working on Ingenic T31
Browse files Browse the repository at this point in the history
  • Loading branch information
wberube committed Jun 5, 2024
1 parent defdced commit 64ae7fd
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 23 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ In spite of these design choices, Divinus boasts numerous features that cater to
| infinity6e[^8] || ✔️ | ✔️ | ✔️ || ✔️ |
| infinity6c[^9] || ✔️ | ✔️ | ✔️ || ✔️ |
| infinity6f[^10] || ✔️ | ✔️ | ✔️ || ✔️ |
| T31 series || | ✔️ | ✔️ || ✔️ |
| T31 series || ✔️ | ✔️ | ✔️ || ✔️ |

_✔️ - supported, ↻ - in development, ✗ - unsupported, ⁿ/ₐ - not supported by hardware_

Expand Down
2 changes: 1 addition & 1 deletion src/app_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ enum ConfigError parse_app_config(void) {
app_config.mp4_codecH265 = false;
}
{
const char *possible_values[] = {"CBR", "VBR", "QP", "AVBR"};
const char *possible_values[] = {"CBR", "VBR", "QP", "ABR", "AVBR"};
const int count = sizeof(possible_values) / sizeof(const char *);
int val = 0;
parse_enum(
Expand Down
145 changes: 129 additions & 16 deletions src/hal/inge/t31_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,7 @@ int t31_video_create(char index, hal_vidconfig *config)
}
switch (config->codec) {
case HAL_VIDCODEC_JPG:
case HAL_VIDCODEC_MJPG:
profile = T31_VENC_PROF_MJPG;
break;
case HAL_VIDCODEC_MJPG: profile = T31_VENC_PROF_MJPG; break;
case HAL_VIDCODEC_H265: profile = T31_VENC_PROF_H265_MAIN; break;
case HAL_VIDCODEC_H264:
switch (config->profile) {
Expand All @@ -330,28 +328,35 @@ int t31_video_create(char index, hal_vidconfig *config)
default: T31_ERROR("This codec is not supported by the hardware!");
}

if (profile == T31_VENC_PROF_MJPG) {
config->framerate = config->gop = 1;
if (ratemode == T31_VENC_RATEMODE_QP) {
config->minQual = config->minQual * (48 - 3) / 99 + 3;
config->maxQual = config->maxQual * (48 - 3) / 99 + 3;
} else config->minQual = config->maxQual = 42;
}

memset(&channel, 0, sizeof(channel));
t31_venc.fnSetDefaults(&channel, profile, ratemode, config->width, config->height,
config->framerate, 1, config->gop, config->gop / config->framerate, -1, config->bitrate);
config->framerate, 1, config->gop, config->gop / config->framerate, -1, 0);

switch (channel.rate.mode) {
case T31_VENC_RATEMODE_CBR:
channel.rate.cbr = (t31_venc_rate_cbr){ .tgtBitrate = MAX(config->bitrate, config->maxBitrate),
.initQual = -1, .minQual = 34, .maxQual = 51, .ipDelta = -1, .pbDelta = -1,
.options = T31_VENC_RCOPT_SCN_CHG_RES | T31_VENC_RCOPT_SC_PREVENTION,
.maxPicSize = config->width }; break;
.initQual = -1, .minQual = 34, .maxQual = 48, .ipDelta = -1, .pbDelta = -1,
.options = T31_VENC_RCOPT_SCN_CHG_RES | T31_VENC_RCOPT_SC_PREVENTION }; break;
case T31_VENC_RATEMODE_VBR:
channel.rate.vbr = (t31_venc_rate_vbr){ .maxBitrate = config->maxBitrate,
.initQual = -1, .minQual = 34, .maxQual = 51, .ipDelta = -1, .pbDelta = -1,
.options = T31_VENC_RCOPT_SCN_CHG_RES | T31_VENC_RCOPT_SC_PREVENTION,
.maxPicSize = config->width }; break;
channel.rate.vbr = (t31_venc_rate_vbr){ .tgtBitrate = config->bitrate,
.maxBitrate = config->maxBitrate, .initQual = -1, .minQual = 34, .maxQual = 48,
.ipDelta = -1, .pbDelta = -1, .options = T31_VENC_RCOPT_SCN_CHG_RES |
T31_VENC_RCOPT_SC_PREVENTION }; break;
case T31_VENC_RATEMODE_QP:
channel.rate.qpModeQual = config->maxQual; break;
channel.rate.qpModeQual = MAX(config->minQual, config->maxQual); break;
case T31_VENC_RATEMODE_AVBR:
channel.rate.avbr = (t31_venc_rate_xvbr){ .maxBitrate = config->maxBitrate,
.initQual = -1, .minQual = 34, .maxQual = 51, .ipDelta = -1, .pbDelta = -1,
.options = T31_VENC_RCOPT_SCN_CHG_RES | T31_VENC_RCOPT_SC_PREVENTION,
.maxPicSize = config->width, .maxPsnr = 42 }; break;
channel.rate.avbr = (t31_venc_rate_xvbr){ .tgtBitrate = config->bitrate, .maxBitrate =
config->maxBitrate, .initQual = -1, .minQual = config->minQual, .maxQual = config->maxQual,
.ipDelta = -1, .pbDelta = -1, .options = T31_VENC_RCOPT_SCN_CHG_RES |
T31_VENC_RCOPT_SC_PREVENTION, .maxPsnr = 42 }; break;
}

if (ret = t31_venc.fnCreateGroup(index))
Expand Down Expand Up @@ -404,6 +409,114 @@ int t31_video_destroy_all(void)
return EXIT_SUCCESS;
}

int t31_video_snapshot_grab(char index, short width, short height,
char quality, hal_jpegdata *jpeg)
{
int ret, fd;
char mjpeg = 0;

if (index == -1) {
fprintf(stderr, "[t31_venc] Snapshot falling back to the MJPEG channel,"
" its resolution will be used in place\n");
for (char i = 0; i < T31_VENC_CHN_NUM; i++) {
if (!t31_state[i].enable) continue;
if (t31_state[i].payload != HAL_VIDCODEC_MJPG) continue;
fd = t31_state[i].fileDesc;
index = i;
mjpeg = 1;
}
return EXIT_FAILURE;
}

if (!mjpeg) {
if (ret = t31_channel_bind(index)) {
fprintf(stderr, "[t31_venc] Binding the encoder channel "
"%d failed with %#x!\n", index, ret);
goto abort;
}

if (t31_venc.fnStartReceiving(index)) {
fprintf(stderr, "[t31_venc] Requesting one frame "
"%d failed with %#x!\n", index, ret);
goto abort;
}

fd = t31_venc.fnGetDescriptor(index);
}

struct timeval timeout = { .tv_sec = 2, .tv_usec = 0 };
fd_set readFds;
FD_ZERO(&readFds);
FD_SET(fd, &readFds);
ret = select(fd + 1, &readFds, NULL, NULL, &timeout);
if (ret < 0) {
fprintf(stderr, "[t31_venc] Select operation failed!\n");
goto abort;
} else if (ret == 0) {
fprintf(stderr, "[t31_venc] Capture stream timed out!\n");
goto abort;
}

if (FD_ISSET(fd, &readFds)) {
t31_venc_stat stat;
if (t31_venc.fnQuery(index, &stat)) {
fprintf(stderr, "[t31_venc] Querying the encoder channel "
"%d failed with %#x!\n", index, ret);
goto abort;
}

if (!stat.curPacks) {
fprintf(stderr, "[t31_venc] Current frame is empty, skipping it!\n");
goto abort;
}

t31_venc_strm strm;
memset(&strm, 0, sizeof(strm));
strm.packet = (t31_venc_pack*)malloc(sizeof(t31_venc_pack) * stat.curPacks);
if (!strm.packet) {
fprintf(stderr, "[t31_venc] Memory allocation on channel %d failed!\n", index);
goto abort;
}
strm.count = stat.curPacks;

if (ret = t31_venc.fnGetStream(index, &strm, 0)) {
fprintf(stderr, "[t31_venc] Getting the stream on "
"channel %d failed with %#x!\n", index, ret);
free(strm.packet);
strm.packet = NULL;
goto abort;
}

{
jpeg->jpegSize = 0;
for (unsigned int i = 0; i < strm.count; i++) {
t31_venc_pack *pack = &strm.packet[i];
unsigned int packLen = pack->length - pack->offset;
unsigned char *packData = (unsigned char*)(strm.addr + pack->offset);

unsigned int newLen = jpeg->jpegSize + packLen;
if (newLen > jpeg->length) {
jpeg->data = realloc(jpeg->data, newLen);
jpeg->length = newLen;
}
memcpy(jpeg->data + jpeg->jpegSize, packData, packLen);
jpeg->jpegSize += packLen;
}
}

abort:
t31_venc.fnFreeStream(index, &strm);
}

if (!mjpeg) {
t31_venc.fnStopReceiving(index);

t31_channel_unbind(index);
}

return ret;
}

void *t31_video_thread(void)
{
int ret;
Expand Down
2 changes: 2 additions & 0 deletions src/hal/inge/t31_hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ int t31_region_setbitmap(int *handle, hal_bitmap *bitmap);
int t31_video_create(char index, hal_vidconfig *config);
int t31_video_destroy(char index);
int t31_video_destroy_all(void);
int t31_video_snapshot_grab(char index, short width, short height,
char quality, hal_jpegdata *jpeg);
void *t31_video_thread(void);

void t31_system_deinit(void);
Expand Down
5 changes: 3 additions & 2 deletions src/hal/inge/t31_venc.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,9 @@ typedef enum {
T31_VENC_RATEMODE_QP,
T31_VENC_RATEMODE_CBR,
T31_VENC_RATEMODE_VBR,
T31_VENC_RATEMODE_CVBR,
T31_VENC_RATEMODE_AVBR
T31_VENC_RATEMODE_LOWLATENCY,
T31_VENC_RATEMODE_CVBR = 4,
T31_VENC_RATEMODE_AVBR = 8
} t31_venc_ratemode;

typedef enum {
Expand Down
3 changes: 2 additions & 1 deletion src/hal/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ typedef enum {
HAL_VIDMODE_VBR,
HAL_VIDMODE_QP,
HAL_VIDMODE_ABR,
HAL_VIDMODE_AVBR
HAL_VIDMODE_AVBR,
HAL_VIDMODE_END
} hal_vidmode;

typedef enum {
Expand Down
26 changes: 24 additions & 2 deletions src/jpeg.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ bool jpeg_module_init = false;

pthread_mutex_t jpeg_mutex;

int jpeg_init() {
int jpeg_init() {
int ret;

pthread_mutex_lock(&jpeg_mutex);

if (app_config.mjpeg_enable) goto mjpeg_active;

jpeg_index = take_next_free_channel(false);

if (ret = create_vpss_chn(jpeg_index, app_config.jpeg_width, app_config.jpeg_height, 1, 1)) {
Expand All @@ -42,12 +44,13 @@ int jpeg_init() {
config.height = app_config.jpeg_height;
config.codec = HAL_VIDCODEC_JPG;
config.mode = HAL_VIDMODE_QP;
config.minQual = app_config.jpeg_qfactor;
config.minQual = config.maxQual = app_config.jpeg_qfactor;

switch (plat) {
case HAL_PLATFORM_I6: ret = i6_video_create(jpeg_index, &config); break;
case HAL_PLATFORM_I6C: ret = i6c_video_create(jpeg_index, &config); break;
case HAL_PLATFORM_I6F: ret = i6f_video_create(jpeg_index, &config); break;
case HAL_PLATFORM_T31: ret = t31_video_create(jpeg_index, &config); break;
case HAL_PLATFORM_V3: ret = v3_video_create(jpeg_index, &config); break;
case HAL_PLATFORM_V4: ret = v4_video_create(jpeg_index, &config); break;
default:
Expand All @@ -64,6 +67,7 @@ int jpeg_init() {
}
}

mjpeg_active:
jpeg_module_init = true;
pthread_mutex_unlock(&jpeg_mutex);
printf(tag "Module initialization completed!\n");
Expand All @@ -73,7 +77,23 @@ int jpeg_init() {

void jpeg_deinit() {
pthread_mutex_lock(&jpeg_mutex);

if (app_config.mjpeg_enable) goto mjpeg_active;

switch (plat) {
case HAL_PLATFORM_I6: i6_video_destroy(jpeg_index); break;
case HAL_PLATFORM_I6C: i6c_video_destroy(jpeg_index, 1); break;
case HAL_PLATFORM_I6F: i6f_video_destroy(jpeg_index, 1); break;
case HAL_PLATFORM_T31: t31_video_destroy(jpeg_index); break;
case HAL_PLATFORM_V3: v3_video_destroy(jpeg_index); break;
case HAL_PLATFORM_V4: v4_video_destroy(jpeg_index); break;
default:
pthread_mutex_unlock(&jpeg_mutex);
return;
}
disable_venc_chn(jpeg_index, 1);

mjpeg_active:
jpeg_module_init = false;
pthread_mutex_unlock(&jpeg_mutex);
}
Expand All @@ -95,6 +115,8 @@ int jpeg_get(short width, short height, char quality, char grayscale,
quality, grayscale, jpeg); break;
case HAL_PLATFORM_I6F: ret = i6f_video_snapshot_grab(jpeg_index, width, height,
quality, grayscale, jpeg); break;
case HAL_PLATFORM_T31: ret = t31_video_snapshot_grab(app_config.mjpeg_enable ?
-1 : jpeg_index, width, height, quality, jpeg); break;
case HAL_PLATFORM_V3: ret = v3_video_snapshot_grab(jpeg_index, width, height,
quality, jpeg); break;
case HAL_PLATFORM_V4: ret = v4_video_snapshot_grab(jpeg_index, width, height,
Expand Down

0 comments on commit 64ae7fd

Please sign in to comment.